ZTXBAS JWT の検証
ユーザーがチャレンジを承認すると、ZTXBAS は短寿命の ES256 JWT を発行し、status 応答に含めます。署名だけでなく、期待した用途に対して有効なトークンであることも確認してください。
JWT の構成
JWT はヘッダーとペイロードを持ちます。主な claims は次のとおりです。
sub、email:認証されたユーザー。aud、origin:チャレンジの対象オリジン。challenge_id:ログの相関に使える 1 回限りのチャレンジ ID。iat、exp:発行時刻と有効期限(通常 5 分)。iss:トークンを発行した ZTXBAS サーバー。
{ "alg": "ES256", "typ": "JWT", "kid": "abc123..." }
{
"iss": "https://ztxbas.example.com",
"sub": "alice@example.com",
"aud": "https://app.example.com",
"iat": 1704067200,
"exp": 1704067500,
"email": "alice@example.com",
"origin": "https://app.example.com",
"challenge_id": "c_abc123"
}
SDK による検証
各 SDK は以下の順序で検証します。
- 3 つの base64url 部分を解析します。
alg == ES256を厳格に確認し、noneを含む他方式を拒否します。- JWKS キャッシュの
kidを参照し、不明・期限切れなら/.well-known/jwks.jsonを再取得します(キャッシュ 5 分)。 header + "." + payloadの ES256 署名を検証します。expが未来であることを確認します(時刻ずれ ±30 秒)。iatが未来に大きくずれていないことを確認します。expected_issuerが設定されていればissも照合します。
いずれかに失敗したトークンは拒否されます。
追加して確認すべき事項
署名、期限、発行者の確認に加えて、バックエンドでは次の点を検証します。
origin が期待したオリジンと一致すること。 他サイト向けに正当に発行された JWT を流用されないようにします。
challenge_id が再利用されていないこと。 JWT はステートレスです。トークン窃取を想定する場合は、最近使ったチャレンジ ID を小規模な LRU キャッシュなどで管理し、再使用を拒否します。JWT を検証後すぐ独自セッション Cookie に交換・破棄する設計では、通常は必須ではありませんが、5 分間の有効期間に注意してください。
if claims.Origin != expectedOrigin {
return errors.New("token issued for a different origin")
}
SDK なしで検証する場合
ES256 と JWKS に対応した標準的な JWT ライブラリを使用してください。公開鍵は /.well-known/jwks.json から取得できます。
kid は再起動しても安定しています。公開鍵の DER エンコードに対する SHA-256 の base64url 表現の先頭 16 文字です。同じ署名鍵を共有するサーバーは同じ kid を生成します。
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"alg": "ES256",
"use": "sig",
"kid": "abc123...",
"x": "base64url...",
"y": "base64url..."
}
]
}
鍵ローテーション
署名鍵をローテーションすると JWKS が複数鍵を返す場合があります。新しいトークンは最新鍵で署名され、旧トークンは通常 5 分以内の exp まで検証可能です。kid を尊重し未知の kid で JWKS を再取得すれば、利用側の特別な操作は不要です。