Reputation: 1853
Just getting started with barryvdh/laravel-cors
. I have a server side application running on port 8000 which authenticates users via Laravel Passport, and my react.js client application running on port 3000. Right now I'm trying to get a "login" action working.
From the client when I provide correct credentials a token is sent back and the status is 200. When the credentials are invalid a 401 is returned. So good so far. However, if I provide only an email in the form and no password I get the following CORS related error:
When the error is thrown, the following network calls occur:
My login on the client side:
login = (email, password) => {
console.log(email);
fetch("http://localhost:8000/api/auth/login", {
method: 'POST',
body: JSON.stringify({
'email': email,
'password': password
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(response => {
console.log(response['access_token']); //with correct credentials this is logged out and set in local storage
localStorage.setItem('access_token', response['access_token']);
})
.catch(error => console.error('Error: ', error));
}
Server side:
public function login(Request $request)
{
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
'remember_me' => 'boolean'
]);
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials)) {
return response()->json([
'message' => 'Unauthorized'
], 401);
}
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me) {
$token->expires_at = Carbon::now()->addWeeks(1);
}
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
}
cors.php
(published from barryvdh/laravel-cors package):
return [
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedOriginsPatterns' => [],
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],
'exposedHeaders' => [],
'maxAge' => 0,
];
api.php
:
Route::group(['prefix' => 'auth',], function () {
Route::post('login', 'AuthController@login');
Route::post('register', 'AuthController@register');
Route::get('register/activate/{token}', 'AuthController@registerActivate');
Route::group(['middleware' => 'auth:api'], function() {
Route::get('logout', 'AuthController@logout');
Route::get('user', 'AuthController@user');
});
});
Kernel.php
:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Barryvdh\Cors\HandleCors::class,
'throttle:60,1',
'bindings',
],
];
protected $middleware = [
\Barryvdh\Cors\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class
];
Making the same POST request (one to /api/auth/login
with the password excluded) via postman I get the expected error message:
{
"message": "The given data was invalid.",
"errors": {
"password": [
"The password field is required."
]
}
}
But, making this through the react client application the error in the screenshot is thrown. I'm guessing this has something to do with the preflight HTTP OPTIONS request that the browser sends out as part of how CORS works.
How can I correct this? I'd expect a 401 to be returned for the status and for the react client to get the same JSON message that Postman receives in the case that the password is empty. It just seems weird that based on the payload for that POST request, a CORS related error occurs. Does this mean that the server and/or client is not setting up CORS correctly?
Upvotes: 0
Views: 1719
Reputation: 1533
It seems that the error is thrown when an error occurs in your backend.
As mentioned in the docs :
When an error occurs, the middleware isn't run completely. So when this happens, you won't see the actual result, but will get a CORS error instead.
This issue helped figuring the source of the error
Upvotes: 3
Reputation: 2103
First of all the class member:
protected $middleware
Will apply the middleware for both api
and web
From laravel.com/docs/5.8/middleware#registering-middleware
If you want a middleware to run during every HTTP request to your application, list the middleware class in the $middleware property of your app/Http/Kernel.php class.
See also: barryvdh/laravel-cors#global-usage
So try to register your middleware one time by removing:
\Barryvdh\Cors\HandleCors::class
of your 'api'
middleware group.
And for logical purposes refactor your protected $middleware
with:
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\Barryvdh\Cors\HandleCors::class,
];
Upvotes: 1