DevToolBox

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

最終更新日: 2026-10-15公開日: 2026-04-19執筆: DevToolBox編集部

JsonWebTokenError: invalid signature やsignature verification failed は JWT を扱うサーバで最も多いエラーの一つです。 原因は 5 つに大別でき、切り分け順さえ決めれば短時間で特定できます。

30秒で分かる答え / Quick answer

症状
JWT の検証で invalid signature や signature verification failed が表示されます。
原因
発行側と検証側の鍵や署名方式が合っていない、鍵の識別子を解決できない、トークンの文字列が壊れているなどが原因です。
対処
ヘッダと本文を確認し、署名方式、鍵の識別子、iss・aud・exp・nbf を順に照合します。すべて正しくても失敗する場合は、発行側と検証側の鍵が一致しているか確認します。

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.

JWT Decoder

署名検証に失敗したトークンを貼り付けて、ヘッダーのalgとペイロードを確認。HS256の署名検証もその場で試せます。

今すぐ試す →

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)
図1: 署名検証失敗の切り分けフロー
JWT署名検証失敗の原因を切り分ける診断フローheader/payloadの確認から始め、algの一致、kidの解決、iss/aud/exp/nbfの検証を順に確認し、いずれかで不一致があればその原因を、すべて一致してもなお失敗するなら鍵の不一致を疑うという5段階の診断フローを示す図JWT Decoderでheaderとpayloadを確認algは検証側allow-listと一致するか?kidをJWKSで解決できるか?iss/aud/exp/nbfは正しいか?すべてOKでも失敗→ 鍵(secret/public key)不一致を疑う(最頻出)invalid algorithm(alg混同を疑う)kid未解決(鍵ローテーション)audience invalid /jwt expiredNoNoNo

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. JWKSキャッシュと鍵ローテーションのタイミング問題 / JWKS caching and key rotation timing

JWKSエンドポイントのレスポンスは、毎回の検証で取得し直すとレイテンシが増えるため、 多くのクライアントライブラリが一定時間キャッシュします。鍵をローテーションした直後は、 新しいkidで署名されたトークンが届いても、検証側のキャッシュがまだ 古いJWKSを保持していてkidを解決できない、という失敗が起こり得ます。

6. 署名対象のバイト列が一致しているか確認する / Verifying the exact signed bytes

JWTの署名はbase64url(header) + "." + base64url(payload)という受け取った文字列そのものに対して計算されています。自前のJWT実装で、 headerやpayloadを一度オブジェクトへデコードしてから再エンコードし、 その再エンコード結果に対して署名検証をしてしまうと、JSONキーの並び順や空白の違いだけで バイト列が変わり、改ざんが無くても署名不一致になります。

// 危険な実装: デコード→オブジェクト化→再エンコードしてから検証
const [h, p, s] = token.split(".");
const header = JSON.parse(base64UrlDecode(h));
const payload = JSON.parse(base64UrlDecode(p));
const reEncoded = base64UrlEncode(JSON.stringify(header)) + "." + base64UrlEncode(JSON.stringify(payload));
verify(reEncoded, s); // 元のバイト列と一致しない可能性がある

// 正しい実装: 受け取った生のheader.payload文字列に対して検証する
const [h2, p2, s2] = token.split(".");
verify(`${h2}.${p2}`, s2);

標準的なJWTライブラリ(jsonwebtoken、PyJWT等)は内部で正しく生のセグメント文字列を 扱っているため、この問題は基本的に発生しません。自前でJWTの検証ロジックを書いている場合に 特有の落とし穴です。

7. 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.

よくある質問 / FAQ

invalid signature と signature verification failed の違いは?
両方とも署名とペイロードが一致しないことを意味します。ライブラリによって文言が違うだけで、原因は鍵不一致・alg不一致・改ざん・エンコード崩れのいずれかです。
What causes 'invalid signature' in JWT?
Either the signing key differs from the verification key, the algorithm differs, the token was tampered with, or the token string was corrupted (e.g. extra whitespace, URL-encoded twice).
HS256 と RS256 は混ぜて使えるか?
混ぜてはいけません。alg allow-listを検証側で固定し、トークンの alg ヘッダに依存しないこと。none 攻撃・alg 混乱攻撃の原因になります。

参考資料 / References

関連ツール / Related tools

関連ガイド / Related guides