API の認証を調べていると、リクエストヘッダーや Cookie に eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMyJ9.xxxx のような長い文字列が登場することがあります。これが JWT(JSON Web Token) です。
この記事では、JWT の仕組みと構造、デコード方法、よくある使いどころとセキュリティの注意点を整理します。
JWT とは
JWT(読み方: ジョット)は、情報を JSON 形式で安全にやりとりするためのコンパクトなトークン形式です。RFC 7519 として標準化されており、主に Web API の認証・認可に使われています。
JWT の最大の特徴は、サーバーがトークンを検証できる点です。署名(Signature)を確認することで、トークンが改ざんされていないかどうかをサーバーサイドで判断できます。
JWT の構造
JWT は .(ドット)で区切られた3つのパートから構成されています。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiJ1c2VyLTEyMyIsImlhdCI6MTY5OTk5OTAwMCwiZXhwIjoxNzAwMDg1NDAwfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
各パートはそれぞれ Base64URL エンコードされています(詳しくは後述)。
| パート | 内容 | 説明 |
|---|---|---|
| Header | {"alg":"HS256","typ":"JWT"} | アルゴリズムとトークン種別 |
| Payload | {"sub":"user-123","exp":...} | ユーザーIDや有効期限などのクレーム |
| Signature | ハッシュ値 | ヘッダー+ペイロードの署名。改ざん検証に使う |
Base64URL エンコードとは
JWT の各パートは Base64URL でエンコードされています。Base64 との違いは、URL に含められない文字(+→-、/→_)が置き換えられている点です。パディング文字(=)も省略されます。
Base64URL は暗号化ではなく、単なるエンコードです。デコードすれば誰でも中身を読めます。JWT の安全性はあくまで Signature の検証によって担保されており、ペイロードの内容は原則として秘匿されていません。
ペイロードの主要クレーム
ペイロードには「クレーム(Claims)」と呼ばれるキーバリューが格納されます。RFC で定義された予約済みクレームの代表例を示します。
| クレーム | 意味 | 型 |
|---|---|---|
exp | 有効期限(Expiration Time) | UNIX タイムスタンプ(秒) |
iat | 発行日時(Issued At) | UNIX タイムスタンプ(秒) |
nbf | 有効開始日時(Not Before) | UNIX タイムスタンプ(秒) |
sub | トークンの主体(Subject) | 文字列(ユーザーID など) |
iss | 発行者(Issuer) | 文字列(URL など) |
aud | 受信者(Audience) | 文字列または配列 |
jti | 一意識別子(JWT ID) | 文字列 |
exp(有効期限)は特によく使われます。現在の UNIX タイムスタンプと exp を比較することで、トークンが期限切れかどうかを判断できます。
// 期限切れチェック(JavaScript)
const now = Math.floor(Date.now() / 1000);
const isExpired = now > jwtPayload.exp;
console.log(isExpired ? '期限切れ' : '有効');
よくある使いどころ
API の認証(Bearer トークン)
最も一般的な使い方は、HTTP リクエストの Authorization ヘッダーに付与する Bearer トークンとしての使用です。
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
サーバーは受け取ったトークンの署名を検証し、exp が未来であれば認証済みとして処理します。
Cookie への格納
SPA(シングルページアプリ)では HttpOnly Cookie に JWT を格納するパターンも一般的です。JavaScript から直接アクセスできないため、XSS による窃取リスクが下がります。
SSO・マイクロサービス間の認証
サービス間で共通の秘密鍵または公開鍵ペアを共有することで、JWT を使ったシングルサインオンや、マイクロサービス間の認証が実現できます。
JWT をデコードする方法
ペイロードの内容を確認したい場合は、. で分割して2番目のパートを Base64URL デコードするだけです。
// JavaScript でデコード
function decodeJWT(token) {
const payload = token.split('.')[1];
// Base64URL → Base64 に変換してデコード
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
return JSON.parse(atob(base64));
}
const decoded = decodeJWT('eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyLTEifQ.xxx');
console.log(decoded); // { sub: 'user-1' }
手動でデコードする場合はツールを使う方が簡単です。
セキュリティの注意点
- ペイロードは暗号化されていない: デコードすれば誰でも読めます。パスワードや機密情報をペイロードに入れないでください。
- 署名なし(alg: none)のトークンは危険: 一部の古いライブラリは
alg: noneを受け入れてしまいます。使用するライブラリが適切に検証しているか確認してください。 - 有効期限を短く設定する:
expを短め(15〜60分程度)に設定し、リフレッシュトークンと組み合わせるのがベストプラクティスです。 - オンラインツールへの本番トークンの貼り付けに注意: 個人情報や認証情報が含まれるトークンをオンラインツールに入力する場合は、セキュリティポリシーを確認してください。
まとめ
- JWT は
header.payload.signatureの3パート構成で、各パートは Base64URL エンコード - ペイロードは暗号化されていないため、機密情報を入れてはいけない
exp(有効期限)・iat(発行日時)・sub(主体)が主要なクレーム- デコードには
.で分割して Base64URL デコードするだけでよい