API が JWT に対して 401 Unauthorized を返すとき、私は payload を眺めながら推測しません。HTTP header から始め、time claims、signature、issuer、audience、token type の順に authentication chain を追います。
expected issuer / audience が分かっているなら JWT デバッガー で最初に比較します。
Step 1: Authorization header を最初に見る
暗号処理の前に request を確認します。
Authorization: Bearer eyJ...
ここで確認するのは:
Bearerがない- token に余計な quote が付いている
- 間違った header に送っている
- token が空または途中で切れている
- copy 時に余計な whitespace / line break が入った
- client が古い token variable を使っている
- access token の代わりに refresh token / ID token を送っている
header が壊れていれば JWT validation まで到達せず 401 になるため、ここを最初に除外します。
Step 2: decode して仮説を作る
JWT デコーダー で:
algkidissaudexpnbf- scopes / roles
を読みます。
decode は診断材料です。payload が読めたことを authentication success とは扱いません。
Step 3: exp と nbf を確認する
時間の問題は早めに除外できます。
exp が過去なら有力な原因です。nbf が未来なら token はまだ active ではありません。JWT 有効期限チェック で NumericDate と server time を比較します。
RFC 6750 の invalid_token は expired だけでなく revoked、malformed、その他 invalid token にも使われるため、generic 401 を expiration と決めつけません。
Step 4: 信頼する key で signature を verify する
時間が問題なければ cryptographic verification に進みます。
確認するのは:
- application が許可する algorithm は何か
- trusted issuer はどこか
- その issuer の secret / public key は何か
kidが現在の trusted key set のどれに対応するか
よくある失敗は、別 environment の key、古い JWKS cache、key rotation、許可されないアルゴリズム、token bytes の改変です。
HS256/384/512 や RS256/384/512 を確認するなら JWT 署名検証 を使います。失敗したら invalid signature ガイド の順番で追います。
401 を消すために signature verification を無効化することはしません。
Step 5: issuer を比較する
例えば token が:
{ "iss": "https://login.dev.example.com/" }
なのに production が:
https://login.example.com/
を期待しているなら、environment / trust domain の取り違えが濃厚です。
同時に、verification に使った key source がその issuer に結び付いているか確認します。
Step 6: audience を比較する
signature が正しく issuer も正しくても、別 API 向けなら拒否されます。
API expects: api://orders
Token aud: api://billing
この場合 audience check を緩めず、token の取得方法または API config を直します。詳しくは JWT audience mismatch ガイド を使います。
Step 7: token type を確認する
OIDC の ID token を resource API に送るミスはよくあります。
手掛かりは:
audが API ではなく client ID- expected API scope がない
- issuer は正しいのに API だけ拒否する
- frontend が別の token variable を Authorization header に入れている
JWT らしい形だから同じ用途だとは考えません。
Step 8: 401 と authorization failure を分ける
一般には:
- 401 → credential / authentication が受け入れられない
- 403 → identity は通ったが permission がない
という手掛かりになります。ただし framework 依存もあるため、authentication checks が通ったら scope、role、resource policy を確認します。
Step 9: server-side validation log を読む
外側から token を確認した後、server log の具体的な error が役立ちます。
signature verification failed
issuer mismatch
audience mismatch
token expired
not yet valid
kid not found
insufficient scope
full bearer token を log せず、error category、expected issuer / audience、kid など必要最小限を残します。
私の 401 debugging order
Authorization: Bearerheader を確認する。- JWT を decode して header / claims を読む。
exp/nbfと server clock を確認する。- trusted key で signature を verify する。
issを trusted issuer と比較する。audを API audience と比較する。- access token / ID token の取り違えを確認する。
- scope / role / permission を見る。
- server の exact validation error を読む。
- validation を無効化せず、失敗している config / acquisition step を直す。
この順番で分かるのは、JWT は完全に decode できても、実際の authentication checks では失敗し得るということです。401 を解決するには、resource server がどの rule を実際に enforce しているかを見つけます。