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
}

標準クレーム:

クレーム名称説明
issIssuerトークン発行者
subSubjectトークンの対象(ユーザーID等)
audAudienceトークンの受信者
expExpiration有効期限(UNIXタイムスタンプ)
iatIssued At発行日時
nbfNot Beforeこの時刻より前は無効
jtiJWT IDトークンの一意識別子

これに加えて、nameroleemailなどのカスタムクレームを追加できます。

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. リフレッシュトークン期限切れ → 再ログイン

セキュリティの注意点

やってはいけないこと

  1. Payloadに機密情報を入れない: JWTのPayloadはBase64URLエンコードされているだけで、暗号化されていません。誰でもデコードして中身を読めます。パスワード、クレジットカード番号などは絶対に含めないでください。

  2. アルゴリズムをnoneにしない: "alg": "none" を許可すると、署名なしのトークンが有効になってしまいます。

  3. 秘密鍵を弱くしない: HS256の秘密鍵は少なくとも256ビット(32文字以上)のランダムな文字列を使いましょう。

  4. 有効期限を長くしすぎない: アクセストークンは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認証において不可欠な技術です。覚えておくべきポイントは以下の通りです。

  1. 3パート構成: Header.Payload.Signature
  2. Payloadは暗号化されない: Base64URLエンコードなので中身は読める
  3. 短い有効期限 + リフレッシュトークン: セキュリティと利便性の両立
  4. RS256推奨: マイクロサービスでは公開鍵/秘密鍵方式が安全

JWTの中身を確認したいときは、JWTデコードツールを使えばHeader・Payload・署名をワンクリックで確認できます。

この記事の内容はAssistyJWTデコードで実際にお試しいただけます。