WebアプリやモバイルアプリにおけるJWT(JSON Web Token)は、現代の認証基盤を支えるコア技術です。
この記事では、JWTの3パート構造から始まり、OpenID Connect・Amazon Cognito・AWS STSとの関係、公開鍵暗号方式による署名検証の仕組み、そしてサーバーが公開鍵を取得するタイミングまでを体系的に解説します。「なんとなく使っているJWTをちゃんと理解したい」エンジニアの方に最適な内容です。
なぜJWTが必要なのか?
WebアプリやモバイルアプリではユーザーがOKかを確かめる認証が欠かせません。しかしユーザー数が増えるにつれて「毎回データベースを検索して確認する」方式では処理が重くなっていきます。

JWTを使えば、サーバーはデータベースに問い合わせることなく、トークン自体を検証するだけでユーザーを識別できます。これがJWTが広く普及している最大の理由です。
JWTの構造
JWT(JSON Web Token)は3つのパートがドット(.)で区切られた文字列です。RFC 7519として国際標準化されています。

| パート | 内容 | 主なフィールド |
|---|---|---|
| ヘッダー | 署名アルゴリズム・鍵IDなどのメタ情報 | alg, kid |
| ペイロード | ユーザー情報・有効期限などのクレーム | sub, exp, iss, aud |
| 署名 | 改ざんされていないことを証明する | 秘密鍵で生成されたハッシュ値 |
⚠️ 重要:各パートはBase64URLエンコードされているだけで暗号化されていません。ペイロードの中身は誰でもデコードして読めます。パスワードなどの機密情報は絶対に含めないでください。
OpenID ConnectとOAuth 2.0
JWTの発行に深く関わる2つのプロトコルを整理します。
| プロトコル | 役割 | 扱うもの |
|---|---|---|
| OAuth 2.0 | 「このアプリに〇〇へのアクセスを許可する」という認可の仕組み | 何ができるか |
| OpenID Connect(OIDC) | OAuth 2.0の上に「誰であるか(認証)」の仕組みを追加したプロトコル | 誰が |
つまり OpenID Connect = OAuth 2.0 + 認証 です。Amazon CognitoはこのOIDCに準拠しており、認証後にJWT形式のIDトークンを発行します。
Amazon CognitoとJWT発行の仕組み
Amazon Cognitoはユーザー認証を管理するAWSのサービスです。ログインが成功するとOIDCの仕様に従い、以下の3種類のトークンを発行します。
- IDトークン(JWT):「このユーザーは誰か」という身元情報。ユーザーID・メールアドレス・有効期限などが含まれる。
- アクセストークン:APIを呼び出すための権限証明。
- リフレッシュトークン:IDトークン・アクセストークンの有効期限が切れた際に再発行するために使う。
CognitoがJWTの署名を作る仕組みは以下のとおりです。
// JWT ヘッダー(デコード後)
{
"alg": "RS256", // 署名アルゴリズム(RSA + SHA-256)
"kid": "abc123" // この署名に使った秘密鍵のID
}
// 署名の生成イメージ
署名 = RSA秘密鍵で暗号化(
SHA256( Base64URL(ヘッダー) + "." + Base64URL(ペイロード) )
)公開鍵暗号方式による署名検証
JWTの署名検証には公開鍵暗号方式が使われます。秘密鍵と公開鍵の役割を理解することが署名検証の核心です。
| 鍵の種類 | 所有者 | 用途 | 公開可否 |
|---|---|---|---|
| 秘密鍵(Private Key) | Cognitoのみ | 署名の「作成」 | 絶対に非公開 |
| 公開鍵(Public Key) | 誰でも取得可能 | 署名の「検証」 | JWKSエンドポイントで公開 |
秘密鍵で作成した署名は、対応する公開鍵でしか検証できません。これにより「この署名はCognitoが作ったもの」と誰でも確認できます。
CognitoはOIDCの標準仕様に従い、公開鍵の一覧を以下のURLで公開しています。
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json// レスポンス例(公開鍵の一覧)
{
"keys": [
{
"kid": "abc123", // JWTヘッダーのkidと照合する
"kty": "RSA",
"alg": "RS256",
"n": "uBp47VGURf...", // 公開鍵の値
"e": "AQAB"
}
]
}💡 印鑑証明に例えると…Cognitoの秘密鍵=本人だけが持つ「印鑑」、JWTの署名=その印鑑を押した「印影」、JWKSエンドポイント=「印鑑証明が登録された役所」。検証する側は役所で公開されている印鑑証明(公開鍵)と実際の印影(署名)を照合するだけです。毎回Cognitoに問い合わせる必要はありません。
署名検証の仕組みを深掘りする
ヘッダーとペイロードはBase64URLエンコードされているだけで、中身は誰でも読めます(暗号化ではありません)。署名だけが秘密鍵で暗号化されています。署名検証は以下の2経路で行われます。
受け取ったJWT
┌───────────────────────────────────────┐
│ヘッダー │ ペイロード │ 署名 │
└───────────────────────────────────────┘
│ │ │
└──────┬────────┘ │
↓ ↓
SHA-256でハッシュ化 公開鍵で復号(kidで特定した公開鍵を使用)
↓ ↓
ハッシュ値B ハッシュ値A
│ │
└────── 比較 ───────┘
↓
A === B → ✅ 検証成功(本物&改ざんなし)
A ≠ B → ❌ 改ざんあり or 偽造トークンこの検証で証明できることは以下の2点です。
- Cognitoが発行した本物のJWT:秘密鍵を持つCognitoだけが正しい署名を作れるため
- ヘッダー・ペイロードが改ざんされていない:改ざんするとハッシュ値Bが変わりAと一致しなくなるため
💡 JWSとJWEの違い:JWTの目的は「データを隠すこと」ではなく「データが本物であることを証明すること」です。内容を隠したい場合はJWE(JWT Encryption)で全体を暗号化します。本物の証明のみが目的であれば、今回解説したJWS(署名)で十分です。通常のIDトークンはJWSで十分とされており、ペイロードに機密情報を含めないことがルールです。
なお、JWTには「一度発行したトークンは有効期限が来るまで無効化できない」という弱点があります。主な対策は以下のとおりです。
- 有効期限を短くする(15分〜1時間程度)← 推奨
- リフレッシュトークンで再発行する仕組みを用意する ← 推奨
- ブラックリスト管理(DBに登録して弾く)← DBアクセスが復活するためトレードオフあり
AWS STSと一時クレデンシャル
AWS STS(Security Token Service)は、AWSリソースへのアクセスに必要な一時的な認証情報(クレデンシャル)を発行するサービスです。
❌ やってはいけないこと:AWSの長期アクセスキーをアプリに直接埋め込むこと。アプリが解析されると認証情報が永続的に漏洩します。
✅ 正しいアプローチ:CognitoでJWTを取得 → STSに渡して有効期限付きの一時クレデンシャルを発行してもらう。
CognitoのJWTからSTSクレデンシャルを得るまでの流れは以下のとおりです。
- ユーザーがCognitoでログイン → CognitoがJWT(IDトークン)を発行してアプリに返す
- アプリがSTSのAPI(AssumeRoleWithWebIdentity)を呼び出す
- STSがCognitoのJWKSエンドポイントから公開鍵を取得してJWTを検証する(Cognitoへの直接問い合わせは不要)
- STSが一時クレデンシャルを返す
- アプリが一時クレデンシャルでAWSリソースにアクセス(有効期限が切れたら②から再実行)
aws sts assume-role-with-web-identity
--role-arn arn:aws:iam::123456789:role/MyAppRole
--web-identity-token <CognitoのIDトークン>
--role-session-name MySession// STSから返される一時クレデンシャル
{
"AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/...",
"SessionToken": "AQoDYXdzE...",
"Expiration": "2026-04-17T13:00:00Z" // 有効期限(例:1時間)
}💡 フェスティバルの入場に例えると…Cognito=チケット販売所(JWT発行)、STS=会場の入口スタッフ(チケット確認&リストバンド発行)、リストバンド=有効期限付きの一時クレデンシャル。期限が来たら再発行が必要で、万一盗まれても一定時間後に無効になります。
WebアプリでのJWT送受信と検証
通常のWebアプリでも同じ公開鍵検証の仕組みが使われます。クライアントは一般的にHTTPの Authorizationヘッダーにトークンを含めて送信します。
GET /api/profile HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
↑ "Bearer"=「このトークンを持参した人に権限を与えてください」サーバー側でのJWT検証は以下のステップで行います。
- AuthorizationヘッダーからJWTを取り出す
- JWTをヘッダー・ペイロード・署名に分割する
- ヘッダーのkidで対応する公開鍵を特定する
- 公開鍵で署名を検証する(改ざん検出)
- ペイロードのクレームを検証する
- すべてOKならリクエストを処理する
ステップ5で確認すべきクレームは以下のとおりです。
| クレーム | 意味 | 確認しないと… |
|---|---|---|
| exp | 有効期限 | 期限切れトークンが使い回される |
| iss | 発行者 | 別サービスのJWTで偽装できてしまう |
| aud | 対象者 | 他サービス向けJWTが使われてしまう |
| sub | ユーザーID | どのユーザーか特定できない |
サーバーはいつ公開鍵を取得するのか
JWTが届くたびにJWKSエンドポイントへアクセスしていたらネットワーク通信が大量に発生します。実際には3つのパターンがあります。
| パターン | 取得タイミング | 注意点 |
|---|---|---|
| ① サーバー起動時に取得 | 起動時にJWKSから公開鍵を取得してメモリにキャッシュ | 鍵ローテーション時に古い鍵を使い続けるリスクがある |
| ② 初回リクエスト時に取得(Lazy Loading) | 最初のJWT検証が来たときに初めて取得してキャッシュ | 起動を軽くしたい場合に有効。ローテーション対応は①と同様 |
| ③ kidが見つからないとき再取得(推奨) | キャッシュにkidがなければJWKSを再取得してキャッシュ更新 | 鍵ローテーションに自動追従できる。多くのライブラリが採用 |
鍵ローテーションとは、Cognitoが使用する秘密鍵を定期的に切り替えることです。kidが変わるため、キャッシュに存在しない場合は再取得が必要になります。
// 鍵の更新前
Cognito: kid="abc" の秘密鍵でJWTに署名 → アプリに発行
// 鍵の更新後(ローテーション)
Cognito: kid="xyz" の秘密鍵でJWTに署名 → アプリに発行
↑ kidが変わる!キャッシュに"xyz"がなければ再取得が必要JWKSエンドポイントのレスポンスには通常 Cache-Control ヘッダーが含まれます。
Cache-Control: public, max-age=3600
↑ 1時間キャッシュを推奨(例)💡 実際の開発では、Node.jsなら jsonwebtoken + jwks-rsa、Javaなら java-jwt などのJWT検証ライブラリがキャッシュ管理・再取得ロジックを自動で処理してくれます。実務では自前実装することはほぼありません。
まとめ
| 用語・概念 | 役割・意味 |
|---|---|
| JWT | ヘッダー・ペイロード・署名の3部構成トークン |
| OpenID Connect | OAuth 2.0に認証を追加した標準プロトコル |
| Amazon Cognito | OIDCに準拠したユーザー認証サービス |
| 秘密鍵 / 公開鍵 | 秘密鍵で署名「作成」、公開鍵で署名「検証」 |
| kid | 対応する公開鍵を特定するための鍵ID |
| AWS STS | JWTを検証して一時クレデンシャルを発行 |
| 署名検証の仕組み | ①署名を公開鍵で復号→ハッシュ値A、②ヘッダー+ペイロードをSHA-256→ハッシュ値B、A=Bなら検証成功 |
| JWSとJWE | JWS=署名で本物を証明(平文)、JWE=全体を暗号化して内容を隠す |
| Bearer認証 | Authorization: Bearer <JWT> ヘッダーで送る |
| 公開鍵の取得タイミング | 「kidが見つからないときだけ再取得」が最も堅牢。鍵ローテーションに自動追従できる |
✨ この記事の最重要ポイント
JWT検証の核心は「発行者に毎回問い合わせることなく、公開鍵だけでローカルに自己完結して検証できる」点にあります。検証の具体的な仕組みは「①署名を公開鍵で復号してハッシュ値Aを得る・②ヘッダー+ペイロードをSHA-256でハッシュしてBを得る・A=Bなら本物と証明」という2経路の比較です。そして公開鍵のキャッシュ管理では、kidが見つからないときだけ再取得することで鍵ローテーションにも自動追従できます。
参考リソース
- RFC 7519 — JSON Web Token (JWT) — JWTの公式標準仕様
- OpenID Connect Core 1.0 — OpenID Connectの公式仕様
- Amazon Cognito 公式ドキュメント — JWTの検証
- AWS STS 公式ドキュメント — AssumeRoleWithWebIdentity
- JWT.IO — JSON Web Token入門


コメント