JWTとは?
JWT(JSON Web Token、ジョットと読む)は、2者間で情報を安全にやり取りするためのトークン形式です。RFC 7519で標準化されています。
主にWebアプリケーションの認証(Authentication)と認可(Authorization)に使われます。ユーザーがログインすると、サーバーがJWTを発行し、以降のリクエストではそのJWTをHTTPヘッダーに含めてAPIを呼び出します。
なぜJWTが使われるのか
従来のセッションベース認証では、サーバー側でセッション情報を保持する必要がありました。JWTはトークン自体に情報を含むため、サーバー側で状態を管理する必要がありません(ステートレス)。これにより以下のメリットがあります。
- スケーラビリティ: 複数サーバーでセッション共有が不要
- マイクロサービス: サービス間でユーザー情報を受け渡しやすい
- モバイルアプリ: Cookieを使わずにトークンベースで認証
JWTの構造
JWTは3つのパートで構成され、ドット(.)で区切られます。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IuWxseeUsOWkqumDjiIsImlhdCI6MTUxNjIzOTAyMn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
1. Header(ヘッダー)
アルゴリズムとトークンの種類を指定します。
{
"alg": "HS256",
"typ": "JWT"
}
alg: 署名アルゴリズム(HS256, RS256, ES256等)typ: トークンタイプ(常にJWT)
2. Payload(ペイロード)
トークンに含めるデータ(クレーム)です。
{
"sub": "1234567890",
"name": "山田太郎",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622
}
標準クレーム:
| クレーム | 名称 | 説明 |
|---|---|---|
iss | Issuer | トークン発行者 |
sub | Subject | トークンの対象(ユーザーID等) |
aud | Audience | トークンの受信者 |
exp | Expiration | 有効期限(UNIXタイムスタンプ) |
iat | Issued At | 発行日時 |
nbf | Not Before | この時刻より前は無効 |
jti | JWT ID | トークンの一意識別子 |
これに加えて、name、role、emailなどのカスタムクレームを追加できます。
3. Signature(署名)
ヘッダーとペイロードを改ざんされていないことを検証するための署名です。
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
秘密鍵を知らない限り、署名を生成できないため、トークンの改ざんを検出できます。
署名アルゴリズムの種類
| アルゴリズム | 種類 | 用途 |
|---|---|---|
| HS256 | 共有鍵(HMAC) | シンプルなアプリ。サーバーが1台の場合 |
| RS256 | 公開鍵/秘密鍵(RSA) | マイクロサービス。公開鍵で検証 |
| ES256 | 公開鍵/秘密鍵(ECDSA) | RS256より軽量。モバイル向き |
推奨: マイクロサービスやサードパーティ連携がある場合は RS256 または ES256 を使いましょう。HS256は秘密鍵を全サービスで共有する必要があるため、鍵漏洩リスクが高くなります。
アクセストークンとリフレッシュトークン
実際のアプリケーションでは、2種類のトークンを組み合わせて使います。
アクセストークン
- 目的: APIリクエストの認可
- 有効期限: 短い(15分〜1時間)
- 保存場所: メモリ内(推奨)
- 含む情報: ユーザーID、権限(role)
リフレッシュトークン
- 目的: アクセストークンの再発行
- 有効期限: 長い(7日〜30日)
- 保存場所: HttpOnly Cookie(推奨)
- 含む情報: ユーザーIDのみ
フロー
1. ログイン → サーバーがアクセストークン + リフレッシュトークンを発行
2. APIリクエスト → Authorization: Bearer <アクセストークン>
3. アクセストークン期限切れ → リフレッシュトークンで再発行
4. リフレッシュトークン期限切れ → 再ログイン
セキュリティの注意点
やってはいけないこと
-
Payloadに機密情報を入れない: JWTのPayloadはBase64URLエンコードされているだけで、暗号化されていません。誰でもデコードして中身を読めます。パスワード、クレジットカード番号などは絶対に含めないでください。
-
アルゴリズムをnoneにしない:
"alg": "none"を許可すると、署名なしのトークンが有効になってしまいます。 -
秘密鍵を弱くしない: HS256の秘密鍵は少なくとも256ビット(32文字以上)のランダムな文字列を使いましょう。
-
有効期限を長くしすぎない: アクセストークンは15分〜1時間程度に設定し、リフレッシュトークンと組み合わせて使います。
ベストプラクティス
exp(有効期限)を必ず設定するiss(発行者)とaud(受信者)を検証する- HTTPSでのみトークンを送信する
- トークンのサイズを小さく保つ(不要なクレームを含めない)
- RS256 / ES256を使い、公開鍵で検証する
JWTの実装例
Node.js(jsonwebtokenライブラリ)
const jwt = require('jsonwebtoken');
// トークン生成
const token = jwt.sign(
{ sub: 'user123', role: 'admin' },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
// トークン検証
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log(decoded); // { sub: 'user123', role: 'admin', iat: ..., exp: ... }
} catch (err) {
console.error('トークンが無効です');
}
Python(PyJWTライブラリ)
import jwt
import datetime
# トークン生成
payload = {
'sub': 'user123',
'role': 'admin',
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
# トークン検証
decoded = jwt.decode(token, 'secret', algorithms=['HS256'])
まとめ
JWTは現代のWeb認証において不可欠な技術です。覚えておくべきポイントは以下の通りです。
- 3パート構成: Header.Payload.Signature
- Payloadは暗号化されない: Base64URLエンコードなので中身は読める
- 短い有効期限 + リフレッシュトークン: セキュリティと利便性の両立
- RS256推奨: マイクロサービスでは公開鍵/秘密鍵方式が安全
JWTの中身を確認したいときは、JWTデコードツールを使えばHeader・Payload・署名をワンクリックで確認できます。
この記事の内容はAssistyのJWTデコードで実際にお試しいただけます。