signing key の変更前後だけ JWT verification が失敗するなら、私は単純な invalid signature ではなく key lifecycle problem として見ます。token 自体も verifier 自体も正しく、old/new key の overlap、kid selection、JWKS cache のどこかで handoff が壊れていることがあります。
知りたいのは:
この token を sign した key を、その token の残り lifetime 中に verifier が見つけて trust できるか?
です。
JWT と current key set があるなら JWKS Validator で kid match と signature を確認します。
Step 1: kid、issuer、expiration を最初に読む
{
"alg": "RS256",
"kid": "signing-key-2026-09"
}
payload では:
{
"iss": "https://login.example.com/",
"exp": 1789203600
}
を見ます。
最初に欲しい facts は:
- key を所有すべき issuer。
- token が指定する
kid。 - token があとどれくらい verify される必要があるか。
RFC 7517 でも kid は JWK Set から key を選ぶため、特に rollover で使える identifier として扱われます。
Step 2: current JWKS と kid を比較する
planned rotation 中は old/new public key が一時的に共存することがあります。
{
"keys": [
{ "kid": "signing-key-2026-06", "kty": "RSA", "alg": "RS256", "use": "sig" },
{ "kid": "signing-key-2026-09", "kty": "RSA", "alg": "RS256", "use": "sig" }
]
}
old token がまだ valid なのに old key が current JWKS から消えているなら:
- key removal が早すぎる。
- token が想定より古い。
- wrong issuer / environment を見ている。
などを確認します。
planned rollover と emergency revocation を分ける
planned rotation なら、通常は already-issued token が age out するまで old verification key を残す設計が自然です。
しかし key compromise 後の emergency rotation なら old key を trust し続けること自体が危険です。その場合、exp が未来でも old key signed token を即時 reject する policy があり得ます。
したがって「old key は必ず全 token expiry まで残す」という universal rule は作りません。
JWKS cache を調べる
issuer は new key を正しく publish しているのに verifier が stale set を持つことがあります。
私は:
- cache TTL
- unknown
kidで controlled refresh するか - gateway/framework に別 cache layer があるか
- multiple instances が独立 cache を持つか
- CDN/proxy が stale metadata を返していないか
- error 後に old set を pin していないか
を確認します。
missing kid で refresh する場合も、fetch 先は already trusted JWKS location に限定します。token data に arbitrary URL を決めさせません。
new key が同じ trusted issuer のものか確認する
trust path は:
expected issuer
↓
trusted metadata/config
↓
trusted JWKS
↓
matching kid
↓
compatible JWK
↓
signature verification
です。
production issuer の token に staging JWKS を使って偶然似た kid があっても成功とはみなしません。issuer validation ガイド で issuer-to-JWKS relationship を確認します。
kid match 後も key metadata を見る
{
"kty": "RSA",
"kid": "signing-key-2026-09",
"use": "sig",
"alg": "RS256"
}
token algorithm と key type が compatible か、use / key_ops が operation と矛盾しないか確認します。
allowed algorithm は application config で pin し、JWT header の alg をそのまま policy にしません。
token lifetime と rotation timing を比較する
例:
11:59 old key で token 発行
12:00 new signing key に切替
12:01 old public key を削除
12:30 old token はまだ 29 分 valid
planned rotation ならこれは verification gap になります。
old public key の overlap は maximum token lifetime、cache strategy、operational buffer を考慮して決めます。JWT standard だけから自動的に duration が決まるわけではありません。
old/new token の両方で再現する
可能なら:
- rotation 直前の old token
- rotation 直後の new token
を current trusted JWKS で検証します。
これで missing old key、missing new key、stale cache、wrong issuer、rotation とは無関係な signature problem を早く分けられます。
kid not found なら JWT kid ガイド も使います。
rollout のために verification を切らない
new key が届いていないから一時的に signature check を skip する、という修正はしません。
rollout problem は key distribution / cache refresh で直し、security model を変更しません。
healthy planned rotation の形
1. trusted JWKS に new public key を先に publish
2. old public key を残す
3. new private key / kid で新しい token を sign
4. verifier は old/new の両方を verify 可能
5. old-token acceptance window が終わるまで待つ
6. policy 上 safe になったら old key を remove
exact timing は IdP、token lifetime、cache、incident policy に依存します。
私の key-rotation checklist
- JWT の
iss/alg/kid/expを読む。 - expected issuer を確認する。
- issuer の trusted current JWKS を見る。
- token
kidが存在するか確認する。 kty/alg/use/key_opsを確認する。- JWKS Validator で signature を test する。
- JWKS cache age / refresh behavior を確認する。
- old-token lifetime と old-key availability を比較する。
- planned rollover と emergency revocation を分ける。
- fix 中も signature verification を維持する。
JWT key rotation は private key を交換するだけではありません。token lifetime、public-key publication、key selection、cache refresh、issuer trust を coordination する作業です。