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 が公開している公開鍵

流れ

  1. ユーザーが Google アカウントで対象アプリにログインする
  2. Google が秘密鍵で ID トークンに署名して発行する
  3. アプリは Google の JWKS(https://www.googleapis.com/oauth2/v3/certs)から公開鍵を取得し、JWT ヘッダの kid に合う鍵で署名を検証する
  4. あわせて次の項目も必ず確認する
    • 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

流れ

  1. GitHub Actions のジョブが、GitHub から ID トークン(JWT)を取得する
  2. ジョブが AWS STS の AssumeRoleWithWebIdentity に ID トークンを渡す
  3. AWS が GitHub の JWKS から公開鍵を取得し、署名を検証する
  4. IAM ロールの信頼ポリシーの条件を満たせば、一時的な認証情報が返る

信頼ポリシーでの条件指定

どのリポジトリ・ブランチからのトークンを受け入れるかは、IAM ロールの信頼ポリシーで条件として指定します。

  • aud: 宛先が AWS(例: sts.amazonaws.com)であること
  • sub: リポジトリやブランチなどを示す値(例: repo:<org>/<repo>:ref:refs/heads/main)が期待どおりであること

sub の条件を緩くしすぎると、意図しないリポジトリからもロールを引き受けられてしまうため、できるだけ具体的に絞ります。