Help us understand the problem. What is going on with this article?

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

環境

概要

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
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした