Prevent Laravel API from processing the token if it enters the URL as a query string

I can process the token if it hits the URL as a query string or if it is included in the header as Authentication , while the token has a prefix with Bearer , and I only want to be able to get it in the header.

This is my app/Http/Controllers/API/V1/AuthenticationController.php file:

 <?php namespace app\Http\Controllers\API\V1; use Illuminate\Http\Request; use App\Http\Controllers\Controller; use Tymon\JWTAuth\Exceptions\JWTException; use App\Models\Role; use App\Models\User; use App\Traits\Controllers\ApiParseBody; use App\Traits\Controllers\ApiException; use App\Traits\Controllers\ApiEvaluateCredentials; use Tymon\JWTAuth\JWTAuth; use App\Exceptions\Unauthorized\InvalidCredentials; use App\Exceptions\InternalServerError\CouldNotCreateToken; use Illuminate\Contracts\Hashing\Hasher; class AuthenticationController extends Controller { use ApiParseBody; use ApiEvaluateCredentials; use ApiException; /** * The user implementation. * * @var User */ protected $user; /** * The role implementation. * * @var Role */ protected $role; /** * The hash implementation. * * @var Hash */ protected $hash; /** * The jwtauth implementation. * * @var JWTAuth */ protected $jwtauth; /** * Instantiate a new controller instance. * * @return void */ public function __construct( User $user, Role $role, Hasher $hash, JWTAuth $jwtauth ) { $this->middleware('jwt.auth', ['except' => ['signin', 'signup']]); $this->user = $user; $this->role = $role; $this->hash = $hash; $this->jwtauth = $jwtauth; } /** * Signin user. * * @param Request $request * * @return Response */ public function signin(Request $request) { $attributes = array('email', 'password'); $credentials = $this->parseBody($attributes, $request); $this->validateCredentialsArePresent($credentials); try { if (! $token = $this->jwtauth->attempt($credentials)) { throw new InvalidCredentials('invalid_credentials'); } } catch (JWTException $e) { throw new CouldNotCreateToken('could_not_create_token'); } return response()->json(compact('token')); } /** * Signup user. Default role is 'common'. * * @param Request $request * * @return Response */ public function signup(Request $request) { $attributes = array('email', 'password'); $params = $this->parseBody($attributes, $request); $this->validateCredentialsArePresent($params); $this->evaluateCredentials($params); $credentials = array( 'email' => $params['email'], 'password' => $this->hash->make($params['password']) ); $this->validateUserAlreadyExists($credentials); $commonRole = $this->role->where('name', 'common')->firstOrFail(); $user = new User($credentials); $commonRole->users()->save($user); return response()->json(array( 'message' => 'User signed up.')); } } 

This is my config/cors.php :

 <?php return [ 'defaults' => [ 'supportsCredentials' => false, 'allowedOrigins' => [], 'allowedHeaders' => [], 'allowedMethods' => [], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => [], ], 'paths' => [ 'v1/*' => [ 'allowedOrigins' => ['*'], 'allowedHeaders' => [ 'Origin', 'Content-Type', 'Accept', 'Authorization', 'X-Request-With' ], 'allowedMethods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], 'exposedHeaders' => ['Authorization'], 'maxAge' => 3600, ], ], ]; 

The following images will show what I mean, just in case I did not understand what I was trying to convey.

This shows how I use Postman to execute a GET for an application on Heroku. You will see that I am using the Authorization header:

enter image description here

And what I want to prevent is to get the same result by sending a token to the URL as follows:

enter image description here

I don’t even know if this is possible, so I would really appreciate any guidance on this.

+5
source share
2 answers

What I did was create middleware to reject all requests with a β€œtoken” as a key parameter in the request.

First we need to create middleware:

php artisan make:middleware BeforeMiddleware and, as you can see, this is middleware, which means that it will be launched before the request gets into the application:

 <?php namespace App\Http\Middleware; use Closure; use App\Exceptions\BadRequest\RejectTokenAsQuerystring; class BeforeMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @return mixed */ public function handle($request, Closure $next) { if ($request->token) { throw new RejectTokenAsQuerystring('reject_token_as_querystring'); } return $next($request); } } 

I also had to add the middleware that I created for my kernel:

 <?php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { /** * The application global HTTP middleware stack. * * These middleware are run during every request to your application. * * @var array */ protected $middleware = [ \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, \Barryvdh\Cors\HandleCors::class, ]; /** * The application route middleware groups. * * @var array */ protected $middlewareGroups = [ 'api' => [ 'throttle:60,1', 'bindings', ], ]; /** * The application route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ 'reject-token-in-url' => \App\Http\Middleware\BeforeMiddleware::class, 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class, 'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class, ]; } 

And finally, middleware that is defined globally can be used in defining my routes as:

 <?php /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ Route::group( [ 'domain' => getenv('API_DOMAIN'), 'middleware' => ['cors', 'reject-token-in-url'], 'prefix' => '/v1', 'namespace' => 'V1' ], function () { } ); 

I also implemented my own error definition, so I have a list of all the possible errors that I want to cause in my application, and they are defined as follows in my config/errors.php :

 <?php return [ "reject_token_as_querystring" => [ "title" => "Reject token as querystring.", "detail" => "Token MUST be passed in the Header of the request." ] ]; 

Then you need to define your own exception class:

 <?php namespace App\Exceptions; use Exception; abstract class CustomException extends Exception { /** * The id of the error that is being triggered. * * @var string */ protected $errorId; /** * Status code for the triggered error. * * @var string */ protected $status; /** * Title of the error. * * @var string */ protected $title; /** * Detailed description about the error. * * @var string */ protected $detail; /** * Instantiate a new Exception with the provided message. * * @param @string $message * * @return void */ public function __construct($message) { parent::__construct($message); } /** * Get the status * * @return Int */ public function getStatus() { return (int) $this->status; } /** * Return the Exception as an array * * @return Array */ public function toArray() { return [ 'id' => $this->id, 'status' => $this->status, 'title' => $this->title, 'detail' => $this->detail ]; } /** * Build the Exception. * * @param array $args * * @return string */ protected function build(array $args) { $this->id = array_shift($args); $error = config(sprintf('errors.%s', $this->id)); $this->title = $error['title']; $this->detail = vsprintf($error['detail'], $args); return $this->detail; } } 

And you will use this class to extend custom errors:

 <?php namespace App\Exceptions\BadRequest; use App\Exceptions\CustomException; class BadRequestException extends CustomException { /** * Status error number. * * @var string */ protected $status = '400'; /** * Instantiate a new 'bad request exception'. * * @return void */ public function __construct() { $message = $this->build(func_get_args()); parent::__construct($message); } } 

To create a class that contains an error:

 <?php namespace App\Exceptions\BadRequest; use App\Exceptions\BadRequest\BadRequestException; class RejectTokenAsQuerystring extends BadRequestException { } 

Finally, if you try to request information with a token key in the URL, you will get:

 { "id": "reject_token_as_querystring", "status": "400", "title": "Reject token as querystring.", "detail": "Token MUST be passed in the Header of the request." } 

enter image description here

+2
source

Put this middleware in app/Http/Middleware/GetUserFromToken.php . This replaces the default middleware with the ability to ignore the token in the query string. This middleware is 99% the default. Just take a look and you will understand how it works.

Then replace

 'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class, 

with

 'jwt.auth' => \App\Http\Middleware\GetUserFromToken::class, 

Intermediate

 <?php namespace App\Http\Middleware; use Tymon\JWTAuth\Middleware\BaseMiddleware; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; class GetUserFromToken extends BaseMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, \Closure $next) { $this->auth->setRequest($request); try { $this->auth->parseToken('bearer', 'authorization', ''); } catch (JWTException $e) { return $this->respond('tymon.jwt.absent', 'token_not_provided', 400); } try { $user = $this->auth->authenticate(); } catch (TokenExpiredException $e) { return $this->respond('tymon.jwt.expired', 'token_expired', $e->getStatusCode(), [$e]); } catch (JWTException $e) { return $this->respond('tymon.jwt.invalid', 'token_invalid', $e->getStatusCode(), [$e]); } if (! $user) { return $this->respond('tymon.jwt.user_not_found', 'user_not_found', 404); } $this->events->fire('tymon.jwt.valid', $user); return $next($request); } } 
0
source

All Articles