LoginSignup
18
16

More than 3 years have passed since last update.

Laravel での tymon/jwt-auth による JWT トークンの自動更新

Last updated at Posted at 2019-10-24

環境

概要

JWT トークンはトークン自体に有効期限が埋め込まれており、期限を更新するにはトークン自体を置き換えなければならない。
フロントで有効期限を管理してトークンのリフレッシュをせずに、スライディングセッションを実現したい。

トークンは Cookie でフロントに保存するものとする。サーバー側で期限切れを検出したら新しいトークンを Cookie に設定してあげる。

トークンの有効期限(JWT_TTL:デフォルト1時間)が切れても、リフレッシュ有効期限(JWT_REFRESH_TTL:デフォルト2週間)内であればそのトークンを用いて新しいトークンを発行することができる。

ログインシーケンス

トークン更新シーケンス

実装

サーバー側でトークンの有効期限切れを検出し、リフレッシュをおこなって返すミドルウェアを作成する。不正なトークンや更新に失敗したりした場合はこのあとの通常処理で 401 になるので、何もしない。

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

class RefreshToken extends BaseMiddleware
{
    public function handle($request, Closure $next)
    {
        $token = $newToken = null;
        try {
            $token = $this->auth->parseToken();
            $token->authenticate();
        } catch (TokenExpiredException $e) {
            // Token expired: try refresh
            try {
                $newToken = $token->refresh();
            } catch (JWTException $e) {
                // Refresh failed (refresh expired)
            }
        } catch (JWTException $e) {
            // Invalid token
        }

        $response = $next($request);
        if ($newToken) {
            // Send the refreshed token back to the client.
            $response->withCookie(cookie(
                'token',
                $newToken,
                config('jwt.refresh_ttl'), // minutes
                null, // path
                null, // domain
                $request->getScheme() === 'https', // secure
                true // httpOnly
            ));
        }
        return $response;
    }
}

このミドルウェアを有効にする。

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    ...
    protected $middlewareGroups = [
        'api' => [
            ...
            \App\Http\Middleware\RefreshToken::class, // JWTトークン更新 ※bindings の前に置く
            'bindings',
            ...
        ],
    ];
}

ブラックリスト猶予期間を設定

リフレッシュがおこなわれると、即時古いトークンは使えなくなるため、フロントから同時に複数のリクエストをおこなった場合、一部のリクエストが失敗してしまう可能性がある。これを防止するため、一定時間は古いトークンも使用できるようにする。.env にブラックリスト猶予期間(JWT_BLACKLIST_GRACE_PERIOD)を設定しておく。(例: 15秒)

JWT_BLACKLIST_GRACE_PERIOD=15
18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16