DevToolBox

JWTの署名検証に失敗する原因と対処

JsonWebTokenError: invalid signaturesignature 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

1. 切り分けの順序 / Diagnostic order

  1. トークンを JWT Decoder で開く(payload と header を確認)
  2. header の alg と検証側の allow-list を比較
  3. header の kid を JWKS エンドポイントで解決できるか確認
  4. iss, aud が想定値か
  5. exp, nbf の時刻とサーバ時計の差(clock skew)

2. 原因別パターン / Cause table

症状 / Symptom原因 / Cause対処 / Fix
invalid signature鍵不一致 / Key mismatch発行側と検証側で同じ secret / public key を使う
invalid algorithmalg mismatchalgorithms: ['RS256'] で allow-list 固定
unable to find a signing key that matches 'kid'JWKS 未更新 / key rotationJWKS キャッシュをflush。発行側と検証側の期間を確認
jwt audience invalidaud 不一致検証側の audience オプションを実値と合わせる
jwt expiredexp切れ / clock skewNTPで時刻同期、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

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.

関連ツール / Related tools

関連ガイド / Related guides