JWTについて
アクセス制御、認証、認可で使われるJWTについて理解を深めたいと思い記事にしました。
そもそもJWTとは?
- JSON Web Tokenの略
- WebアプリやAPIで「認証・認可情報を安全に持ち運ぶためのコンパクトなトークン」
- 自己完結型(トークン自体に必要な情報が詰まっている)のが特徴
- 属性情報(
Claim)をJSONデータ構造で表現したトークン仕様を指す。
1.JWTの全体構造
まずJWTの全体の構造について簡単な図で説明したい。
体系イメージ
┌────────────┐
│ JWT (JSON Web Token) ← 仕様の“総称” │
└─────┬───────┘
│
├── JWS (JSON Web Signature) = 署名付きトークン
│ └─ header.payload.signature という見慣れた3部構成
│
└── JWE (JSON Web Encryption) = 暗号化付きトークン
└─ header.暗号化鍵.IV.暗号化payload.認証タグ など5部構成
- JWT:JSON形式のクレームを安全委持ち運ぶための規格全体。
- JWS:JWTを「署名」で保護する方式(改ざん検知のみ)
- JWE:JWTを「暗号化」で保護する方式(秘匿+改ざん検知)
2.JWTのルール
実際のJWTのルールについて大きく3つに分けて説明する
① 構造に関するルール
- 以下の例(JWS)のように
.(ピリオド)で区切る。
header.payload.signature
- Header・PayloadはBase64URLエンコードされる(改行や
+ではなく-、_を使うURL安全な形式) - SignatureはHeader+Payloadを秘密鍵で署名したもの
② クレーム(Claim)に関するルール
Payloadに入れるデータ(クレーム)には予約語がある
-
iss(issuer): 発行者 -
sub(subject): 主体(ユーザーIDなど) -
aud(audience): 対象 -
exp(expiration): 有効期限(秒単位UNIXタイム) -
iat(issued at): 発行時刻→ これらの予約クレーム名は仕様で定義済み。自由に追加するカスタムクレームもOK
③ セキュリティに関するルール
- 秘密情報はPayloadに入れない(暗号化されていないので誰でも読める)。
-
署名アルゴリズムを固定する(Headerの
algを信頼しない。サーバー側で強制する)。 - 有効期限を必ず設定する(無期限トークンは危険)。
- HTTPS通信必須(平文HTTPで送らない)。
- トークンの失効管理(必要ならブラックリスト、短命アクセストークン+リフレッシュトークン)。
3.典型的な使われ方・利用用途
ここでは簡単ではあるが、典型的な使われ方や利用されるシーンについて説明したい。
使われ方
- ユーザーがログイン→サーバーがJWTを発行
- クライアント(ブラウザやアプリ)がJWTを保存(CookieやLocalStrageなど)
- APIアクセス時にJWTを送信(Authorizationヘッダなど)
- サーバー側は署名検証してユーザーを特定
利用用途
- OAuth 2.0、OpenID Connectなどの認証プロトコルにおけるトークン
- Cokkieを使うのが難しいマイクロサービスやモバイルアプリでのセッション管理
- シングルサインオン(SSO)での認証
- RESTful APIの認証
- ステートレス認証
4.JOSEとは?
JWTには暗号化や署名に関してのルールがある。
この大事なルールを定めた規格をJOSE(JSON Object Signing and Encryption)という。
そして、署名に関するルールをJWS、暗号化に関するルールをJWEと呼ぶ。
本記事では広く使われているJWSのみを説明しようと思う。
JWSとは?
-
ルール
ルール自体はJWTのルールと同じ
-
役割
-
Payloadに**署名(Signature)**を付けて、改ざんされていないことを保証する。
→ 改ざん検知
-
中身は誰でも読める(暗号化はしていない)。
-
いま一般的に使われているJWTはほぼ全部この形
-
-
使用例
1.Header
{ "alg": "HS256", "typ": "JWT" }-
alg:署名アルゴリズム(ここではHMAC SHA-256) -
typ:トークンの種類(JWT)
2.Payload
{ "sub": "1234567890", // ユーザーID "name": "user", "role": "admin", "iat": 1695187200, // 発行時刻 (UNIXタイム) "exp": 1695190800 // 有効期限 }- 署名付きだけど暗号化はされない → 誰でもBase64URLデコードすれば中身は見える
-
subやexpなどは予約クレーム
3.Signature
Header + Payload を秘密鍵で署名したもの。
(Base64URLエンコードしたHeaderとPayloadを結合して署名)
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c4.JWT全体
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjk1MTg3MjAwLCJleHAiOjE2OTUxOTA4MDB9. SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c- 3つの部分が
.で区切られたJWS形式 - サーバーは
Signatureを検証して「改ざんされていないか」をチェック - Payloadを読み取り、ユーザーIDや権限を判断
-
5.まとめ
JWTは「自己完結した署名付きデータ」を持ち回ることで、サーバーに状態を持たずに認証・認可ができる仕組み。
署名と暗号化の違い、Payload設計、期限管理などの“ルール”を守ることが安全運用のカギ。
次回は実際に個人開発で詰まったJWT+Cookieの部分を記事にしたいと思います。