JMDC TECH BLOG

JMDCのエンジニアブログです

Laravel11でJWTトークンを使ったユーザー認証で苦戦した話

こんにちは。JMDCインシュアランス本部ソリューション部の檜山です。

最近、初めてLaravel11でJWTトークン認証を実装しました。 実装にあたり私の知見不足により苦戦したことがいくつかありましたので、他山の石として参考になれば幸いです。

環境

Laravel11

使用ライブラリ

GitHub - tymondesigns/jwt-auth: 🔐 JSON Web Token Authentication for Laravel & Lumengithub.com

苦戦したところ①

JWT自体にはリフレッシュトークンの標準的な仕組みは無い

リフレッシュトークンとは、クライアント-サーバ間で認証したのちに発行される期限の短いアクセストークンを更新するために使われる、1回きり使用可能な期間の長いトークンです。詳しくは下記のOAuth 2.0のドキュメントをご参照いただければと思います。

openid-foundation-japan.github.io

tymon/jwt-authでは1つのJWTに「通常の有効期限(ttl)」と「リフレッシュが可能な最大期間(refresh_ttl)」の2つの期限を持たせる設計になっています。 私の認証に対する知見が無かったこともあり、JWTを使った認証と、OAuth 2.0のような認可フローとの違いを理解するのに時間がかかりました...

結局のところトークンは2種類発行したかったため、ログイン認証時に2種類のJWTトークンを発行するよう実装しました。

アクセストークン  :JWT認証、期限短め、何度でも使用可能
リフレッシュトークン:JWT認証、期限長め、1回使用したら無効化

シーケンス

上記実装は力技なところもあるため、OAuth 2.0認可フローの仕組みに寄せるのであれば使用ライブラリはLaravel Passportをお勧めします。

laravel.com

苦戦したところ②

トークンリフレッシュ有効期限にデフォルト値が設定されている

上記の通り、リフレッシュトークンの仕組みを力技で実装し、試験フェーズまで来ました。

試験を進めていくと、「リフレッシュトークン発行から2週間経つとトークンの更新に失敗する」という事象が起きました。調べてみると、トークンのリフレッシュ有効期限がデフォルト値(2週間)になっていることが原因でした。

トークン種別 有効期限種別 期間
アクセストークン 認証有効期限 10分
アクセストークン リフレッシュ有効期限 2週間
リフレッシュトークン 認証有効期限 20日
リフレッシュトークン リフレッシュ有効期限 2週間

※上記有効期限は検証用の値です。

リフレッシュトークン自体の認証はまだ有効期間内のためトークンとしては使えますが、refresh_ttl(リフレッシュ有効期限)を過ぎていたため、新しいトークンの再発行に失敗していました。

苦戦したところ①で力技で実装したと記載しましたが、ライブラリの意図とは異なる実装をしてしまったことが根本原因だと思います。
tymon/jwt-auth は 1トークン運用を前提とした設計思想があるため、2トークン(アクセストークンとリフレッシュトークン)を分けて運用したことが、今回の問題の一因だったと考えています。

下記のように設定値を修正することで、想定通りの挙動をするようになりました。

トークン種別 有効期限種別 期間
アクセストークン 認証有効期限 10分
アクセストークン リフレッシュ有効期限 20日
リフレッシュトークン 認証有効期限 20日
リフレッシュトークン リフレッシュ有効期限 20日

※上記有効期限は検証用の値です。

設定の変更方法

ライブラリのconfigにてJWT_REFRESH_TTLのデフォルト値が20160分(2週間)で設定されています。

github.com

.envファイルにJWT_REFRESH_TTLを設定することでトークンリフレッシュ有効期限を指定することができます!
(下記では28800分=20日)

JWT_REFRESH_TTL=28800 // リフレッシュ有効期限(分) 

まとめ

今回の開発では認証処理の知見不足、使用ライブラリ選定など自分の勉強不足が目立つところがありました。

ただ、実装していく中でライブラリや認証に対する理解を深めていくことができたのは良かったことかなと思います。
今後、認証処理を実装する際にはこの経験を生かし、より適切な認証設計を心掛けたいと思います。