Laravel - Session store not set on request

PhpLaravelSessionSession Cookies

Php Problem Overview


I recently created a new Laravel project and was following along the guide on Authentication. When I visit either my login or register route, I get the following error:

ErrorException in Request.php line 775:
Session store not set on request. (View: C:\Users\Matthew\Documents\test\resources\views\auth\register.blade.php)

I haven't edited any core Laravel files, I've only created the views and added the routes to my routes.php file

// Authentication routes
Route::get('auth/login', ['uses' => 'Auth\AuthController@getLogin', 'as' => 'login']);
Route::post('auth/login', ['uses' => 'Auth\AuthController@postLogin', 'as' => 'login']);
Route::get('auth/logout', ['uses' => 'Auth\AuthController@getLogout', 'as' => 'logout']);

// Registration routes
Route::get('auth/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']);
Route::post('auth/register', ['uses' => 'Auth\AuthController@postRegister', 'as' => 'login']);

I don't have much experience with Laravel, so please excuse my ignorance. I'm aware that there is another question asking this same thing, but neither of the answers seem to work for me. Thanks for reading!

Edit:

Here's my register.blade.php as requested.

@extends('partials.main')

@section('title', 'Test | Register')

@section('content')
    <form method="POST" action="/auth/register">
        {!! csrf_field() !!}
        <div class="ui input">
          <input type="text" name="name" value="{{ old('name') }}" placeholder="Username">
        </div>
        <div class="ui input">
          <input type="email" name="email" value="{{ old('email') }}" placeholder="Email">
        </div>
        <div class="ui input">
          <input type="password" name="password" placeholder="Password">
        </div>
        <div class="ui input">
          <input type="password" name="password_confirmation"placeholder="Confirm Password">
        </div>
        <div>
            <button class="ui primary button" type="submit">Register</button>
        </div>
    </form>
@endsection

Php Solutions


Solution 1 - Php

You'll need to use the web middleware if you need session state, CSRF protection, and more.

Route::group(['middleware' => ['web']], function () {
    // your routes here
});

Solution 2 - Php

If adding your routes inside the web middleware doesn't work for any reason then try adding this to $middleware into Kernel.php

protected $middleware = [
        //...
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
];

Solution 3 - Php

In my case (using Laravel 5.3) adding only the following 2 middleware allowed me to access session data in my API routes:

  • \App\Http\Middleware\EncryptCookies::class
  • \Illuminate\Session\Middleware\StartSession::class

Whole declaration ($middlewareGroups in Kernel.php):

'api' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Session\Middleware\StartSession::class,
            'throttle:60,1',
            'bindings',
        ],

Solution 4 - Php

If Cas Bloem's answer does not apply (i.e. you've definitely got the web middleware on the applicable route), you might want to check the order of middlewares in your HTTP Kernel.

The default order in Kernel.php is this:

$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,
    ],
];

Note that VerifyCsrfToken comes after StartSession. If you've got these in a different order, the dependency between them can also lead to the Session store not set on request. exception.

Solution 5 - Php

A problem can be that you try to access you session inside of your controller's __constructor() function.

From Laravel 5.3+ this is not possible anymore because it is not intended to work anyway, as stated in the upgrade guide.

> In previous versions of Laravel, you could access session variables or > the authenticated user in your controller's constructor. This was > never intended to be an explicit feature of the framework. In Laravel > 5.3, you can't access the session or authenticated user in your controller's constructor because the middleware has not run yet.

For more background information also read Taylor his response.

Workaround

If you still want to use this, you can dynamically create a middleware and run it in the constructor, as described in the upgrade guide:

> As an alternative, you may define a Closure based middleware directly > in your controller's constructor. Before using this feature, make sure > that your application is running Laravel 5.3.4 or above: > > > >
> namespace App\Http\Controllers; >
> use App\User; > use Illuminate\Support\Facades\Auth; > use App\Http\Controllers\Controller; >
> class ProjectController extends Controller > { > /** > * All of the current user's projects. > / > protected $projects; >
> /
* > * Create a new controller instance. > * > * @return void > */ > public function __construct() > { > $this->middleware(function ($request, $next) { > $this->projects = Auth::user()->projects; >
> return $next($request); > }); > } > }

Solution 6 - Php

Laravel [5.4]

My solution was to use global session helper: session()

Its functionality is a little bit harder than $request->session().

writing:

session(['key'=>'value']);

pushing:

session()->push('key', $notification);

retrieving:

session('key');

Solution 7 - Php

In my case I added the following 4 lines to $middlewareGroups (in app/Http/Kernel.php):

'api' => [
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \App\Http\Middleware\VerifyCsrfToken::class,
    'throttle:60,1',
    'bindings',
],

IMPORTANT: The 4 new lines must be added BEFORE 'throttle' and 'bindings'!

Otherwise a "CSRF token not match" error will rise. I've struggled in this for several hours just to find the order is important.

This allowed me to access session in my API. I also added VerifyCsrfToken as when cookies/sessions are involved, CSRF needs to be taken care of.

Solution 8 - Php

I'm using Laravel 7.x and this problem arose.. the following fixed it:

go to kernel.php and add these 2 classes to protected $middleware

\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,

Solution 9 - Php

I was getting this error with Laravel Sanctum. I fixed it by adding \Illuminate\Session\Middleware\StartSession::class, to the api middleware group in Kernel.php, but I later figured out this "worked" because my authentication routes were added in api.php instead of web.php, so Laravel was using the wrong auth guard.

I moved these routes here into web.php and then they started working properly with the AuthenticatesUsers.php trait:

Route::group(['middleware' => ['guest', 'throttle:10,5']], function () {
    Route::post('register', 'Auth\RegisterController@register')->name('register');
    Route::post('login', 'Auth\LoginController@login')->name('login');

    Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail');
    Route::post('password/reset', 'Auth\ResetPasswordController@reset');

    Route::post('email/verify/{user}', 'Auth\VerificationController@verify')->name('verification.verify');
    Route::post('email/resend', 'Auth\VerificationController@resend');

    Route::post('oauth/{driver}', 'Auth\OAuthController@redirectToProvider')->name('oauth.redirect');
    Route::get('oauth/{driver}/callback', 'Auth\OAuthController@handleProviderCallback')->name('oauth.callback');
});

Route::post('logout', 'Auth\LoginController@logout')->name('logout');

I figured out the problem after I got another weird error about RequestGuard::logout() does not exist.

It made me realize that my custom auth routes are calling methods from the AuthenticatesUsers trait, but I wasn't using Auth::routes() to accomplish it. Then I realized Laravel uses the web guard by default and that means routes should be in routes/web.php.

This is what my settings look like now with Sanctum and a decoupled Vue SPA app:

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' => [
        EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'throttle:60,1',
    ],
];

> Note: With Laravel Sanctum and same-domain Vue SPA, you use httpOnly cookies for session cookie, and remember me cookie, and unsecure cookie for CSRF, so you use the web guard for auth, and every other protected, JSON-returning route should use auth:sanctum middleware.

config/auth.php

'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

...

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],

Then you can have unit tests such as this, where critically, Auth::check(), Auth::user(), and Auth::logout() work as expected with minimal config and maximal usage of AuthenticatesUsers and RegistersUsers traits.

Here are a couple of my login unit tests:

TestCase.php

/**
 * Creates and/or returns the designated regular user for unit testing
 *
 * @return \App\User
 */
public function user() : User
{
    $user = User::query()->firstWhere('email', '[email protected]');

    if ($user) {
        return $user;
    }

    // User::generate() is just a wrapper around User::create()
    $user = User::generate('Test User', '[email protected]', self::AUTH_PASSWORD);

    return $user;
}

/**
 * Resets AuthManager state by logging out the user from all auth guards.
 * This is used between unit tests to wipe cached auth state.
 *
 * @param array $guards
 * @return void
 */
protected function resetAuth(array $guards = null) : void
{
    $guards = $guards ?: array_keys(config('auth.guards'));

    foreach ($guards as $guard) {
        $guard = $this->app['auth']->guard($guard);

        if ($guard instanceof SessionGuard) {
            $guard->logout();
        }
    }

    $protectedProperty = new \ReflectionProperty($this->app['auth'], 'guards');
    $protectedProperty->setAccessible(true);
    $protectedProperty->setValue($this->app['auth'], []);
}

LoginTest.php

protected $auth_guard = 'web';

/** @test */
public function it_can_login()
{
    $user = $this->user();

    $this->postJson(route('login'), ['email' => $user->email, 'password' => TestCase::AUTH_PASSWORD])
        ->assertStatus(200)
        ->assertJsonStructure([
            'user' => [
                ...expectedUserFields,
            ],
        ]);

    $this->assertEquals(Auth::check(), true);
    $this->assertEquals(Auth::user()->email, $user->email);
    $this->assertAuthenticated($this->auth_guard);
    $this->assertAuthenticatedAs($user, $this->auth_guard);

    $this->resetAuth();
}

/** @test */
public function it_can_logout()
{
    $this->actingAs($this->user())
        ->postJson(route('logout'))
        ->assertStatus(204);

    $this->assertGuest($this->auth_guard);

    $this->resetAuth();
}

I overrided the registered and authenticated methods in the Laravel auth traits so that they return the user object instead of just the 204 OPTIONS:

public function authenticated(Request $request, User $user)
{
    return response()->json([
        'user' => $user,
    ]);
}

protected function registered(Request $request, User $user)
{
    return response()->json([
        'user' => $user,
    ]);
}

Look at the vendor code for the auth traits. You can use them untouched, plus those two above methods.

  • vendor/laravel/ui/auth-backend/RegistersUsers.php
  • vendor/laravel/ui/auth-backend/AuthenticatesUsers.php

Here is my Vue SPA's Vuex actions for login:

async login({ commit }, credentials) {
    try {
        const { data } = await axios.post(route('login'), {
            ...credentials,
            remember: credentials.remember || undefined,
        });

        commit(FETCH_USER_SUCCESS, { user: data.user });
        commit(LOGIN);

        return commit(CLEAR_INTENDED_URL);
    } catch (err) {
        commit(LOGOUT);
        throw new Error(`auth/login# Problem logging user in: ${err}.`);
    }
},

async logout({ commit }) {
    try {
        await axios.post(route('logout'));

        return commit(LOGOUT);
    } catch (err) {
        commit(LOGOUT);

        throw new Error(`auth/logout# Problem logging user out: ${err}.`);
    }
},

It took me over a week to get Laravel Sanctum + same-domain Vue SPA + auth unit tests all working up to my standard, so hopefully my answer here can help save others time in the future.

Solution 10 - Php

I had the same error but it was due to a misconfiguration in my sanctum.php file. Inside the block for the stateful Domains, I had still a development domain instead of my production domain.

'stateful' => explode(',', env(
        'SANCTUM_STATEFUL_DOMAINS',
        'mydomain.com')
),

It throwed the exact same error.

Hope that helps someone.
Cheers

Solution 11 - Php

Do you can use ->stateless() before the ->redirect(). Then you dont need the session anymore.

Solution 12 - Php

Are you facing this issue when running a test for SPA authentication with sanctum?

Solution:

Add this line to tests/TestCase.php:


    public function setUp(): void
    {
        parent::setUp();
        $this->withHeader('origin', config('app.url'));
    }

Explanation:

In order to use sanctum for SPA auth, you have to add this to api middleware:

\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class

EnsureFrontendRequestsAreStateful class only works when its static method fromFrontend returns true:

 public static function fromFrontend($request)
    {
        $domain = $request->headers->get('referer') ?: $request->headers->get('origin');

        if (is_null($domain)) {
            return false;
        }
        // ... ommited
}

Session store is not set because $domain is null when this method is running on unit tests.

Solution 13 - Php

in my case it was just to put return ; at the end of function where i have set session

Solution 14 - Php

If you are using CSRF enter 'before'=>'csrf'

In your case Route::get('auth/login', ['before'=>'csrf','uses' => 'Auth\AuthController@getLogin', 'as' => 'login']);

For more details view Laravel 5 Documentation Security Protecting Routes

Solution 15 - Php

It's not on the laravel documentation, I have been an hour to achieve this:

My session didn't persist until i used the "save" method...

$request->session()->put('lang','en_EN');
$request->session()->save();

Solution 16 - Php

Laravel 5.3+ web middleware group is automatically applied to your routes/web.php file by the RouteServiceProvider.

Unless you modify kernel $middlewareGroups array in an unsupported order, probably you are trying to inject requests as a regular dependency from the constructor.

Use request as

public function show(Request $request){

}

instead of

public function __construct(Request $request){

}

Solution 17 - Php

In my own case (in Laravel 5.8) the session.php config file in my Laravel project located in the ../[mylaravelapp]/config/ directory was missing. Hence, I copied the missing file from another Laravel project back to the config directory, which fixed the problem.

Solution 18 - Php

Ok, here is what you are facing: You are calling a request association session which is not instantiated to the request you made. You only need to setLaravelSession on the request which will init session on request on which you want to have the session data available.

$request->setLaravelSession(session())

Solution 19 - Php

just add in top public/index.php

ob_start();

it's work with shared host


if not work try change this code in app/Http/Middleware/TrustProxies.php

protected $proxies;

to

protected $proxies = '*';

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmattrickView Question on Stackoverflow
Solution 1 - PhpCas BloemView Answer on Stackoverflow
Solution 2 - PhpWaiyl KarimView Answer on Stackoverflow
Solution 3 - PhpGeorge KaganView Answer on Stackoverflow
Solution 4 - PhpMHGView Answer on Stackoverflow
Solution 5 - PhpDaanView Answer on Stackoverflow
Solution 6 - PhpizzakiView Answer on Stackoverflow
Solution 7 - PhpMarinneView Answer on Stackoverflow
Solution 8 - PhpAseil HamidView Answer on Stackoverflow
Solution 9 - Phpagm1984View Answer on Stackoverflow
Solution 10 - PhpTaranisView Answer on Stackoverflow
Solution 11 - PhpHenrique DuarteView Answer on Stackoverflow
Solution 12 - Phpglinda93View Answer on Stackoverflow
Solution 13 - PhpShawinder Jit SinghView Answer on Stackoverflow
Solution 14 - PhpMissaka IddamalgodaView Answer on Stackoverflow
Solution 15 - PhpgtamboreroView Answer on Stackoverflow
Solution 16 - PhpKanchana RandikaView Answer on Stackoverflow
Solution 17 - Phpuser28864View Answer on Stackoverflow
Solution 18 - Phpkhalil khassepView Answer on Stackoverflow
Solution 19 - PhpWaad MawloodView Answer on Stackoverflow