JWT(JSON Web Token)解説¶
原文¶
JWT
JSON Web Token (JWT) は、クライアントとサーバー間で情報を安全に送信する方法です。ウェブアプリケーションやAPIで使用され、ユーザーの認証を行い、未承認のアクセスを防ぎます。JWTがトークンを生成する際の構造は、ヘッダー、ペイロード、シグネチャーです。
要約¶
JWTはクライアント・サーバー間で情報を安全に送受信するためのトークン形式。3パートで構成:ヘッダー(アルゴリズム情報)、ペイロード(クレーム/ユーザー情報)、シグネチャー(改ざん検知)。サーバーはセッション状態を持たずに認証できるためスケールしやすい。
解説¶
JWTの構造¶
JWTは . で区切られた3つのBase64URLエンコードされた文字列で構成される。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← ヘッダー
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ← シグネチャー
① ヘッダー (Header)¶
② ペイロード (Payload)¶
クレーム(主張)と呼ばれるキー・バリューペアを格納する。
| 種別 | 例 | 説明 |
|---|---|---|
| 登録クレーム | iss, sub, exp, iat |
RFC 7519で定義された標準クレーム |
| パブリッククレーム | name, email |
公開用ユーザー情報 |
| プライベートクレーム | role, tenant_id |
アプリ独自のクレーム |
③ シグネチャー (Signature)¶
シグネチャーにより、トークンが改ざんされていないことを検証できる。ただし、ペイロードはBase64URLエンコードされているだけで暗号化はされていない(JWEを使えば暗号化可能)。
認証フロー¶
クライアント → POST /login (email, password) → サーバー
← JWT (access_token, refresh_token) ←
クライアント → GET /api/data (Authorization: Bearer <JWT>) → サーバー
← サーバーはJWTを検証してレスポンス ←
JWTのメリット・デメリット¶
| 項目 | 内容 |
|---|---|
| メリット | ステートレス(サーバーにセッション不要) |
| スケールしやすい(DBルックアップ不要) | |
| クロスドメイン対応(CORS対策が簡単) | |
| 自己完結型(ペイロードに情報を持てる) | |
| デメリット | トークンの無効化が困難(有効期限まで有効) |
| ペイロードが大きくなると通信量増加 | |
| シークレットキー漏洩で全トークンが危険に |
セキュリティのベストプラクティス¶
- expを必ず設定する: access tokenは短め(15分〜1時間)、refresh tokenは長め(7〜30日)
- ペイロードに機密情報を入れない: パスワード、クレカ番号等はNG
- アルゴリズムは明示的に検証する:
alg: none攻撃への対策 - refresh tokenの失効管理: ローテーションとDB管理でセキュリティ強化
- HTTPS必須: トークンの盗聴を防ぐ
Goでの実装例¶
import "github.com/golang-jwt/jwt/v5"
// トークン生成
claims := jwt.MapClaims{
"sub": userID,
"exp": time.Now().Add(15 * time.Minute).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signedToken, err := token.SignedString([]byte(secretKey))
// トークン検証
parsed, err := jwt.Parse(signedToken, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
return []byte(secretKey), nil
})
→ 関連: 認証と認可の違い、デバイストークンスコープ設計