

JWT認証、アクセストークンとリフレッシュトークンで最低限決めておくこと
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
JWTでアクセストークン+リフレッシュトークンの構成を組むとき、どこを決めればいいのかを一度整理した。
全体の構成
- アクセストークン:JWT、短命(15〜30分程度)。サーバは署名と
expを見るだけでログイン状態を判定できる - リフレッシュトークン:アクセストークン切れ後の再発行用。長命(30日など)
- クライアントは401を受けたらリフレッシュトークンで新しいアクセストークンを取りに行く
sequenceDiagram
participant Client
participant API
Client->>API: リクエスト + アクセストークン
API-->>Client: 401(トークン期限切れ)
Client->>API: リフレッシュトークンで /refresh
API-->>Client: 新アクセストークン(+新リフレッシュトークン)
ここまでは定番。この先の「どこまで作り込むか」で判断が分かれる。
1. 有効期限をどこに置くか
- アクセストークンは短いほど漏洩時の被害が小さいが、リフレッシュの頻度が上がる
- リフレッシュトークンは長いほどユーザーの再ログイン頻度は減るが、漏洩時の窓が広がる
- 「絶対期限(発行から何日まで)」と「スライディング(使い続ける限り延長)」のどちらにするかは別軸。スライディングはUXがいいが、漏洩したトークンも同じ理屈で延命され続ける点に注意。
2. ローテーションをやるか
リフレッシュのたびに新しいリフレッシュトークンを発行して、古い方を即無効化する方式。これを入れないと、漏洩したリフレッシュトークンは期限が切れるまでずっと使われ続ける。
入れる場合は、旧トークンが再利用されたとき(=無効化したはずのトークンで再度リフレッシュ要求が来たとき)の扱いも決めておく。漏洩の証拠とみなして関連トークンを無効化する、いわゆる reuse detection。
3. 管理単位をユーザーにするか端末にするか
ここでハマりやすい。リフレッシュトークンを「ユーザーに1本」で管理すると、複数端末ログイン(スマホとタブレットなど)で片方をリフレッシュしたときに、もう片方のトークンまで巻き込んで無効化してしまう。
端末(セッション)単位で持たせれば解決する。
user_sessions sessionId, userId, deviceInfo, createdAt, lastSeenAt, revokedAt
refresh_tokens tokenId, sessionId, tokenHash, expiresAt, revokedAt, replacedByTokenId- ローテーションで無効化する範囲は「そのセッションの直前のトークンだけ」
- reuse detection で無効化する範囲も「そのセッション配下だけ」(ユーザー全体に広げるかは別のポリシー判断)
- 端末からはリフレッシュトークンと一緒に
sessionIdも送らせると、サーバ側の判定が単純になる
4. 同時リフレッシュの競合をどう抑えるか
端末内で複数リクエストがほぼ同時に401を受けると、リフレッシュが多重に走ることがある。片方がローテーションで新トークンを出した直後に、もう片方が旧トークンでリフレッシュしようとして失敗する。
クライアント側でリフレッシュ処理を single-flight にして、401を受けたリクエストはキューしておき、リフレッシュ成功後にまとめて再送するのが素直な対策。
5. 保存場所をどこにするか
- ネイティブアプリならKeychain(iOS)/Keystore(Android)
- Webならリフレッシュトークンを
localStorageに置くとXSSでそのまま持っていかれる。HttpOnly Cookieに置く場合はCSRF対策(SameSite、CSRFトークンなど)とセット
6. 状態を持つかどうかのトレードオフ
ローテーション後の旧トークン無効化も、reuse detectionも、「どのトークンが最新か」を覚えておく必要がある処理なので、サーバが完全に状態を持たない構成とは原理的に相性が悪い。
状態を持たない方向に振る場合、選択肢はこのあたり:
- リフレッシュトークンもJWTにして
expだけで判定する(強制ログアウトもreuse detectionも諦める前提を受け入れる) - 有効期限を短めにする、端末側の保管を徹底するなど予防策で漏洩時の被害を抑える
- 「失効管理はしたいが自前DBは避けたい」なら、結局どこかにKVS相当の状態は必要になる
運用を軽くしたいか、漏洩時に止血したいかのトレードオフで、要件次第でどちらの構成もあり得る。