JWT
title: JWT description: “Web で使用されるセキュリティトークン JWT についてまとめています。” parent: token —
JWT(JSON Web Token)は、2 者間で情報を安全にやり取りするための、コンパクトで URL セーフなトークン形式です。RFC 7519 で標準化されています。
構造
ヘッダー.ペイロード.署名 の3つを、ドット(.)でつないだ文字列です。各部分は Base64URL でエンコードされています。
- ヘッダー: 署名アルゴリズム(例: HS256、RS256)やトークン種別(JWT)を示す JSON
- ペイロード: クレームと呼ばれる情報の JSON。ユーザー ID(
sub)、発行者(iss)、有効期限(exp)などが入る - 署名: ヘッダーとペイロードを秘密鍵(または共通鍵)で署名したもの。改ざん検知に使う
主な用途
- 認証・認可(ログイン後のアクセストークンとして API に送る)
- OpenID Connect の ID トークン
- サービス間での情報の受け渡し
署名方式
署名するのはトークンの発行側(認可サーバーや IdP)で、検証するのは受け取る側(API やアプリ)です。方式によって使う鍵が異なります。
| 方式 | 代表的なアルゴリズム | 署名に使う鍵 | 検証に使う鍵 | 主な使いどころ |
|---|---|---|---|---|
| 共通鍵 | HS256 | 共有秘密値 | 同じ共有秘密値 | 発行側と検証側が同一の組織・システム内にある場合 |
| 公開鍵 | RS256、ES256 など | 発行側の秘密鍵 | 発行側の公開鍵 | 発行側と検証側が分かれている場合。OIDC の ID トークンは多くがこちら |
- 共通鍵方式では、検証できる側は署名もできてしまうため、検証側を増やしにくい
- 公開鍵方式では、公開鍵を配るだけで多数の検証側が署名の正しさを確認できる
- アクセストークンでも、公開鍵方式(RS256 など)は一般的
特徴と注意点
- サーバー側でセッションを保持しなくても検証できる(ステートレス)
- ペイロードは暗号化ではなくエンコードされているだけなので、誰でも読める。機密情報は入れない
- 署名で改ざんは検知できるが、発行後の失効が難しい。そのため有効期限を短くするのが基本
- 検証時は署名アルゴリズムを固定し、
alg: noneを拒否する。expやissなども必ず確認する
OIDC
例 1:Google ログイン
OIDC の ID トークンは JWT です。多くの場合は公開鍵暗号(RS256 など)で署名されます(仕様上のデフォルトは RS256。HS256 も仕様上は可能だが少数派)。
| 役割 | 誰か | 鍵 |
|---|---|---|
| 署名する側 | IdP(OpenID Provider)= Google | Google の秘密鍵 |
| 検証する側 | RP(Relying Party)= 自分のアプリ | Google が公開している公開鍵 |
流れ
- ユーザーが Google アカウントで対象アプリにログインする
- Google が秘密鍵で ID トークンに署名して発行する
- アプリは Google の JWKS(
https://www.googleapis.com/oauth2/v3/certs)から公開鍵を取得し、JWT ヘッダのkidに合う鍵で署名を検証する - あわせて次の項目も必ず確認する
iss(発行者が Google か)aud(宛先が自分のクライアント ID か)exp(有効期限が切れていないか)nonce(認可リクエスト時に送った値と一致するか)
公開鍵の配り方
https://<IdP>/.well-known/openid-configurationにjwks_uriが書かれている- 署名鍵は定期的にローテーションされるので、公開鍵は固定で持たず、JWKS から取得してキャッシュする(ライブラリに任せればよい)
注意点
- アプリのバックエンドは、OIDC では Google から見たクライアント(RP)にあたる
- JWKS の取得には HTTPS(TLS)を使う。「その公開鍵が本当に Google のものか」は TLS の証明書の仕組みが保証している
- TLS 証明書の鍵と、ID トークンに署名する鍵は別の鍵
- アプリが IdP に自分を証明する方法(クライアント認証)は別の話。
client_secret_basic/client_secret_post(共有シークレット)や、private_key_jwt(アプリ自身の秘密鍵で署名)がある
例 2:GitHub Actions → AWS
GitHub が秘密鍵で署名した ID トークンを、AWS STS が GitHub の公開鍵で検証し、IAM ロールの一時的な認証情報を渡します。長期のアクセスキーを GitHub に置かなくて済みます。
| 項目 | 内容 |
|---|---|
| 署名する側(IdP) | GitHub Actions(発行者 iss は https://token.actions.githubusercontent.com) |
| 検証する側 | AWS STS |
| 呼び出す API | AssumeRoleWithWebIdentity |
流れ
- GitHub Actions のジョブが、GitHub から ID トークン(JWT)を取得する
- ジョブが AWS STS の
AssumeRoleWithWebIdentityに ID トークンを渡す - AWS が GitHub の JWKS から公開鍵を取得し、署名を検証する
- IAM ロールの信頼ポリシーの条件を満たせば、一時的な認証情報が返る
信頼ポリシーでの条件指定
どのリポジトリ・ブランチからのトークンを受け入れるかは、IAM ロールの信頼ポリシーで条件として指定します。
aud: 宛先が AWS(例:sts.amazonaws.com)であることsub: リポジトリやブランチなどを示す値(例:repo:<org>/<repo>:ref:refs/heads/main)が期待どおりであること
sub の条件を緩くしすぎると、意図しないリポジトリからもロールを引き受けられてしまうため、できるだけ具体的に絞ります。