Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Passport Set Session

Getting below error when I am trying to set session by laravel passport

"message": "Session store not set on request.", "exception": "RuntimeException",

like image 722
Alok Kumar Sharma Avatar asked Aug 19 '18 08:08

Alok Kumar Sharma


2 Answers

This can be done in several ways.

1. Add StartSession middleware after auth:api.

This is the most straightforward solution. Add the following three lines right after auth:api.

EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,

Then remove \Illuminate\View\Middleware\ShareErrorsFromSession::class from middlewarePriority protected property. Without this StartSession middleware will get control before auth and, more importantly, before EncryptCookies middlewares which, basically, will always lead to a new session.

<?php

namespace App\Http;

class Kernel extends HttpKernel
{
    // Copy this values from
    // \Illuminate\Foundation\Http\Kernel::$middlewarePriority
    // then remove or comment line with StartSession. Without it,
    // StartSession middleware will get control right before Auth.
    // Which, basically, will create a new session because at this
    // time cookies are still encrypted.
    protected $middlewarePriority = [
        // \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Auth\Middleware\Authenticate::class,
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            ...
        ],
        'api' => [
            'throttle:120,1',
            'bindings',
            'auth:api', // https://laravel.com/docs/5.7/passport#protecting-routes

            // Add the following three middleware right after `auth`
            // in order to have a session.
            EncryptCookies::class,
            AddQueuedCookiesToResponse::class,
            StartSession::class,
        ],
    ];
}

2. Create your own StartSession middleware.

Having your own middleware for starting session will free you from necessaty to override middlewarePriority.

First, create a new class.

<?php

namespace App\Http\Middleware;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Session\SessionManager;

class StartSessionShared extends StartSession
{
    public function __construct(Application $app, SessionManager $manager)
    {
        parent::__construct($manager);
        $app->singleton(StartSessionShared::class);
    }
}

Then add the following three lines right after auth:api.

EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSessionShared::class,

One important note in this method is call to $app->singleton. Without it Laravel will always create a new instance of this class. Which will lead \Illuminate\Session\Middleware\StartSession::terminate method to skip saving session.

3. Create your own StartSessionReadonly middleware.

This is a good choice if you want just to share session from web guard to api guard and don't intend to alter its values in any way. This was my case.

Create the following StartSessionReadonly middleware. Then use it in api guard instead of StartSession and two its friends.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Contracts\Session\Session;
use Illuminate\Http\Request;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Session\SessionManager;

/**
 * Middleware for sharing session between `web` and `api` guards.
 * Since the latter is essentially stateless, the session from
 * `web` is shared as readonly.
 *
 * @package App\Http\Middleware
 */
class StartSessionReadonly extends StartSession
{
    protected $encrypter;

    public function __construct(Encrypter $encrypter, SessionManager $manager)
    {
        parent::__construct($manager);
        $this->encrypter = $encrypter;
    }

    public function handle($request, Closure $next)
    {
        // If a session driver has been configured, we will need to start the session here
        // so that the data is ready for an application. Note that the Laravel sessions
        // do not make use of PHP "native" sessions in any way since they are crappy.
        if ($this->sessionConfigured()) {
            $request->setLaravelSession($this->startSession($request));
        }

        return $next($request);
    }

    public function getSession(Request $request)
    {
        return tap($this->manager->driver(), function (Session $session) use ($request) {
            $payload = $request->cookies->get($session->getName());
            $unserialize = EncryptCookies::serialized($session->getName());
            try {
                $session->setId($this->encrypter->decrypt($payload, $unserialize));
            }
            catch (DecryptException $exception) {
            }
        });
    }
}

After updating app/Http/Kernel.php you will have readonly session for all of your api.

<?php

namespace App\Http;

class Kernel extends HttpKernel
{
    [...]

    /****
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        [...]
        'api' => [
            'throttle:120,1',
            'bindings',
            'auth:api', // https://laravel.com/docs/5.7/passport#protecting-routes
            StartSessionReadonly::class,
        ],
    ];
like image 52
vbarbarosh Avatar answered Sep 29 '22 18:09

vbarbarosh


Laravel Passport is a token-based authentication package for laravel

APIs typically use tokens to authenticate users and do not maintain session state between requests. Laravel makes API authentication a breeze using Laravel Passport, which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes.

Almost all the token-based systems including oAuth2 are by default stateless, which means there is no session attached to it,

Which means there is no session store.You can only rely on the token which is supplied on each request to validate the users identity.

That's why you are not able to set session when using laravel passport

like image 21
Shobi Avatar answered Sep 29 '22 19:09

Shobi