Prevent Laravel API from processing the token if it comes in the URL as querystring
What I did was to create a middleware in order to reject all requests with "token" as a key param in the querystring.
First we have to create the middleware:
php artisan make:middleware BeforeMiddleware
and as you may notice is a before middleware, that means that is going to run before the request hits 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 to my kernel:
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's 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's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's 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 the middleware as is being defined globally can be used in the definition of 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 have implemented my own definition of error, so I have a list of all possible errors that I want to trigger in my application, and they are defined as follows in my config/errors.php
file:
<?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 custom 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 that class to extend your 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);
}
}
In order to create the class that holds the error itself:
<?php
namespace App\Exceptions\BadRequest;
use App\Exceptions\BadRequest\BadRequestException;
class RejectTokenAsQuerystring extends BadRequestException
{
}
Finally if you try to request info with the 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."
}