Im trying to build an api, and for some reason I need sessions. But if I include web middleware I get CSRF errors, and if I dont I cant have session started.
How to solve this?
go to app/Http/Kernel.php and add your own name like 'sessions' to the $middlewareGroups. It should contain \Illuminate\Session\Middleware\StartSession::class,
Assign 'sessions' to those routes you want.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
'sessions' => [
\Illuminate\Session\Middleware\StartSession::class,
]
];
routes/api.php
Route::group(['middleware' => ['sessions']], function () {
Route::resource(...);
});
Well, i killed like 2-3 hours to solve this problem and write checker on python to configure that problem is not in me.
However, lets talk about laravel API and how does it works.
By default laravel API works only with "tokens". If you want to use this ability, you should think about this 2 variants:
You can install "passport" (That's like a manager for your sessions but without session. Insted of em). Like: php artisan passport:install.
You can create column in your database, generate tokens and push em here.
But that's not what are we talking about here, right? Lets talk about really nice solution, that works fine for all verions of laravel.
There is a files, called Kernel.php. They are created for configure your application. By default all API routes will work with this rule:
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
If you want, you can check what is this Middleware about.
So, next step is to recreate 'api' rule.
What do you want to API do? Validate all with session? Validate all with CSRF or without it? Just watch here:
'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,
],
This is config of WEB routes. You can see there some interesting middlewares such:
\App\Http\Middleware\VerifyCsrfToken::class. Now you see, right?
Fixes for your API should looks like:
'api' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
'throttle:api',
],
And if you want with CSRF:
'api' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
App\Http\Middleware\VerifyCsrfToken::class,
'throttle:api',
],
By default base rules (guards) that controll your actions is created at config\auth.php and looks like (for api and web):
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
If you want if the future not to have any problems with this API, you should change this 'rules' in a same way:
'api' => [
'driver' => 'session',
'provider' => 'users',
],
And please, dont forget to CLEAR all, except of .gitignore here: /storage/framework/sessions
Happy coding! :)
To fix for Laravel 6.x, you can use the solution here
Open app\kernel.php
add \Illuminate\Session\Middleware\StartSession::class,
into 'api' => [ 'throttle:60,1', 'bindings', ],
Final outcome will be like this below:
'api' => [
\Illuminate\Session\Middleware\StartSession::class,
'throttle:60,1',
'bindings',
],
When you check your api response, you will see the cookie set in the header.
I got the solution here >> https://laravel.io/forum/laravel-api-using-session-issue
It actually solved it perfectly for me.
Related
I've got the following issue: Whenever I make a single request towards Laravel the same session is used, whenever I make multiple Ajax requests then Laravel keeps creating new sessions.
I applied the StartSession and EncryptCookies middlewares on the API routes. My Kernel looks the following way:
'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' => [
\App\Http\Middleware\EncryptCookies::class,
'bindings',
AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
Does any one have an idea why multiple new sessions are created when in practice the session cookie should get renewed about the already created session.
Http apps are stateless meaning you Sessions are manually handled for multi request.
Clean all session data
$request->session()->flush();
Generate a new session id
$request->session()->regenerate();
Latavel is not a framework that expects
AddQueuedCookiesToResponse::class
Should be:
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class
Here's my Kernel middlewareGroups for reference
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' => [
'throttle:60,1',
\App\Http\Middleware\EncryptCookies::class,
'bindings',
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
];
I have a simple application and I want to be able to change language.
In my main controller I have:
session(['applocale' => 'en']);
$request->session()->put('applocale','en');
I know that these two lines are the same but I want to be sure that they both does not work.
Then I have API method:
public function switchLang(Request $request, $lang)
{
error_log("Current language is: " . session('applocale'));
error_log("Current language is: " . $request->session()->get('applocale'));
}
And here error_log shows nothing.
I'm following this thread: Laravel 5.3 - How to add Sessions to API without CSRF?
And in Debugbar I can see that my API function has hit middleware 'sessions' but session variables are not there.
That's how it's look like my 'seasons' middleware:
'sessions' => [
\Illuminate\Session\Middleware\StartSession::class,
]
It actually hits both 'api' and 'sessions' middleware.
Any ideas what I'm doing wrong?
This works for me (Laravel-5.7 ).
Firstly change the api middleware group to -
'api' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
'throttle:60,1',
'bindings',
],
in App\http\kernel.php .
Reference here.
Good afternoon guys, I'm having an issue I don't know if you have the same trouble, I upgrade my Laravel project and now all routes like this
Route::get('detail/client/{client}', "controller#method")
are breaking everything because the object instanced in the controller comes empty...
public function detail(FileRequest $request, Client $client){
dd($client) // empty object
}
If someone can help me with this please. If I remove the Client model and make the dd then return the ID of the object i.e "594"
You haven't written base Laravel version you are upgrading from, but I think it might have something in common with \Illuminate\Routing\Middleware\SubstituteBindings::class middleware.
Make sure you have it in middlwareGroups like this:
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, // <- this is the line you should have
],
'api' => [
'throttle:60,1',
'bindings',
],
];
in app/Http/Kernel.php file
and also make sure the routes you have problem are in web middleware group.
i am using laravel 5.2 whit the predefined middelwares 'api' and 'web'. in the kernel file its stated that web would use quite some while api only checks throttle:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
in my routes i grouped the api routes and applied only 'api'
Route::group(array('prefix' => 'api', 'middleware' => ['api']), function(){
Route::post('test', 'TestController#testfunction');
}); // End of api Group
but when i send a post to /api/test it throws the crsf token mismatch. if i put the 'api/test' to the exception in the VerifyCsrftoken.php it works again. i cant figure out why the crsf token gets checked if not defined as a middelware for the route. Does anyone has an idea why?
CSRF is a "middleware" registered globally in App\Http\Kernel.php. Removing it will default to no CSRF protection (Laravel4 behavior).
To enable it in a route:
Create a short-hand key in your
app/Providers/RouteServiceProvider.php:
protected $middleware = [
// ....
'csrf' => 'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
];
You can now enable it to any Route:
$router->post('url', ['middleware' => 'csrf', function() {
...
}]);
Not really elegant but may be a spot on on your question, try it.
I have a route group in my routes.php file with the middleware specified like so:
Route::group(['prefix' => 'api', 'middleware' => 'api'], function() {
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});
}
I am using the Lucadegasperi Oauth2 Server addon. For its setup, I had to enter the following LucaDegasperi item in the $middleware array of the Kernel.php file (Kernel class):
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\LucaDegasperi\OAuth2Server\Middleware\OAuthExceptionHandlerMiddleware::class,
];
The $middlewareGroups array of the same class is as follows:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
What the OAuthExceptionHandlerMiddleware does is that it formats exceptions to JSON responses. Now when I apply the 'middleware' => 'api' in the route group as shown, the global middlewares dont work. I can say this because the HTML error page shows when exceptions occur. However, when I omit the 'middleware' => 'api' in the route group, the global middlewares work and I get JSON responses for the errors.
How do I get past this?
The reason for this is due to changes with how Laravel handles exceptions in Middleware from 5.2.7 onwards, as documented in this ticket I raised. To fix this you need to alter your Exception handler (as explained in the issue) or await the latest patch from the package.
I've commmitted a fix to the repository which fixes the issue of the changes made to Laravel 5.2, however this has not yet been merged.
Did you remember to add Authorizer to aliases array?
'Authorizer' => LucaDegasperi\OAuth2Server\Facades\Authorizer::class,
Because you're using it in:
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});