JWTの署名検証に失敗する原因と対処
JsonWebTokenError: invalid signature やsignature verification failed は JWT を扱うサーバで最も多いエラーの一つです。 原因は 5 つに大別でき、切り分け順さえ決めれば短時間で特定できます。
invalid signature and signature verification failed are the most common JWT errors on the server side. There are five typical causes; a fixed diagnostic order gets you to the root quickly.
TL;DR
- 鍵不一致 / key mismatch が最頻出(発行側と検証側で別の鍵を使っている)
alg不一致 / algorithm mismatch(HS256 と RS256 を混同)- JWKS の
kidが解決できない / key rotation failure aud,iss,exp,nbfの検証失敗- トークンの文字列が途中で壊れた(URLエンコード2回・空白混入)
1. 切り分けの順序 / Diagnostic order
- トークンを JWT Decoder で開く(payload と header を確認)
- header の
algと検証側の allow-list を比較 - header の
kidを JWKS エンドポイントで解決できるか確認 iss,audが想定値かexp,nbfの時刻とサーバ時計の差(clock skew)
2. 原因別パターン / Cause table
| 症状 / Symptom | 原因 / Cause | 対処 / Fix |
|---|---|---|
invalid signature | 鍵不一致 / Key mismatch | 発行側と検証側で同じ secret / public key を使う |
invalid algorithm | alg mismatch | algorithms: ['RS256'] で allow-list 固定 |
unable to find a signing key that matches 'kid' | JWKS 未更新 / key rotation | JWKS キャッシュをflush。発行側と検証側の期間を確認 |
jwt audience invalid | aud 不一致 | 検証側の audience オプションを実値と合わせる |
jwt expired | exp切れ / clock skew | NTPで時刻同期、clockTolerance: 5 |
invalid token (3分割失敗) | 文字列破損 / Base64URL崩れ | URLエンコード2重化、Bearer プレフィクスの削除漏れを確認 |
3. 言語別の検証コード / Verification in each language
Node.js (jsonwebtoken)
import jwt from "jsonwebtoken";
const payload = jwt.verify(token, publicKey, {
algorithms: ["RS256"], // allow-list 必須
issuer: "https://example.com",
audience: "api.example.com",
clockTolerance: 5,
});Python (PyJWT)
import jwt
payload = jwt.decode(
token, public_key,
algorithms=["RS256"],
issuer="https://example.com",
audience="api.example.com",
leeway=5,
)Go (github.com/golang-jwt/jwt)
tok, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected alg")
}
return publicKey, nil
})4. セキュリティ上の注意 / Security notes
- alg: none を許可しない。allow-list で明示拒否
- HS256 と RS256 の混在禁止。公開鍵を HMAC secret として渡すと署名偽造される
- 検証前に
decodeだけで使わない。必ずverifyを通す
5. English summary
"invalid signature" on a JWT almost always falls into five categories: key mismatch between issuer and verifier, algorithm mismatch (HS vs RS), unresolved kid after rotation, aud/iss mismatch, and exp/nbfdrift from clock skew. Always pin an algorithm allow-list on the verifier, refresh JWKS on rotation, and never trust the token's own alg header. For inspection, use a decoder to read header and payload without verifying, then compare against your verifier config.