初心者向けJWT講座:JSON Web Tokenを使った認証の仕組み
JWTって何?
JWTはJSON Web Tokenの略です。
まずは完成されたJWTを見てみましょう。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
この文字列がJWTです。
JWTの特徴を見てみる
よく見ると、この文字列は 「.」(ドット) で区切られています。
JWTは次の3つのパーツから構成されています。
- ヘッダ(Header)
- ペイロード(Payload)
- 署名(Signature)
ただの文字列じゃない?
JWTは単なる文字列ではありません。
実は、この「ヘッダ」や「ペイロード」をデコードすると、JSON形式のデータとして扱えるのです。
JWTの構造を見てみよう
この3つのパーツの内容を順番に詳しく見ていきましょう。
1. ヘッダ(Header)
JWTの「ヘッダ」には、トークンの基本情報が記載されています。
具体的には、署名に使用するアルゴリズムやトークンの種類などが含まれます。
{
"alg": "HS256",
"typ": "JWT"
}
この例では
- alg:署名に使われるアルゴリズム(この場合は HS256)
- typ:トークンの種類(JWT)
が含まれています。
このJSONデータはBase64Urlエンコードされ、次のような文字列になります。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
2. ペイロード(Payload)
「ペイロード」は、トークンに含めたいデータ(クレーム)が記載される部分です。
この部分がトークンの本体で、例えば次のような情報を含むことができます。
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
それぞれの意味は、
- sub:トークンの対象者(ユーザーIDなど)
- name:名前
- iat:トークンが発行された日時(UNIXタイムスタンプ)
です。
個々の項目名をクレームと呼びます。
このJSONデータもBase64Urlエンコードされ、次のような文字列になります。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
3. 署名(Signature)
最後に「署名」です。この部分は、JWTの改ざんを防ぐために使用されます。
署名は次の手順で生成されます。
- ヘッダとペイロードを連結して文字列を作る。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
- この文字列を、指定されたアルゴリズム(例: HMAC-SHA256)と秘密鍵で署名する。
すると以下のような文字列が作成されます。
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
完成されたJWTの全体像
以上の3つのパーツを「.」(ドット)で連結すると、JWTが完成します。
<Header>.<Payload>.<Signature>
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JSONに戻してみよう
ヘッダとペイロードはBase64Urlエンコードされているだけなので、誰でも簡単に元のJSON形式に戻せます。
例えば、ペイロード部分をデコードすると次のようになります。
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
JWTは
- だれでもJSONに戻して内容を確認できる
- ただし署名があるため改ざんを検知できる
という特徴を持ちます。
JWTは中身を見られないようにしたり改ざんできないようにするためのものではなく、改ざんを検知するための仕組みです。
このJWTを用いることで認証の仕組みを作ることができます。
JWT認証とは?
ログインと聞くと、アプリケーション側が「ログイン状態」を管理するイメージがありませんか?
例えば
- ユーザーがログインすると、アプリケーションはセッション情報を記録します。
- このセッションを使って「このユーザーはログイン済み」と判断します。
この仕組みは「セッションベースの認証」と呼ばれます。
アプリケーションがログイン状態をサーバー側で管理しているのが特徴です。
JWT認証は『トークンベース認証』
一方、今回学ぶJWTは「トークンベース認証」です。
トークンベース認証では、アプリケーション側がログイン状態を保持しません。
「じゃあ、どうやってログイン状態を管理するの?」と思いますよね?
JWTを使った認証の仕組み
トークンベース認証では、次のような流れでユーザーを識別します。
1. JWT(トークン)を発行
ユーザーがログインすると、アプリケーションはユーザー専用の「JWT」というトークンを発行します。
これが「ログイン状態を証明するパスポート」のような役割を果たします。
2. JWTをリクエストに含める
ユーザーがデータを取得したり操作したりする際、リクエストにこのJWTを毎回含めて送ります。
3. アプリケーションがJWTを検証
サーバー側では、リクエストを受け取るたびにJWTが有効かどうかを確認します。
JWTが正しければ「このリクエストは正規のユーザーから来たものだ」と判断します。
JWTが正しいかどうかは署名を確認します。
JWT認証の流れを見てみる
具体的にJWT認証がどのように動作するのかを見ていきましょう。
1. ログイン時にJWTを発行する
ユーザーはメールアドレスとパスワードなどの認証情報をサーバーに送ります。
POST /login HTTP/1.1
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123"
}
サーバーは送信されたメールアドレスとパスワードを確認します。
- 認証が成功した場合はJWTを生成します。
- JWTのペイロードには、ユーザーの情報や有効期限などを含めます。
{
"sub": "1234567890", // ユーザーID
"name": "John Doe",
"iat": 1610000000, // 発行時刻
"exp": 1610003600 // 有効期限 (1時間後)
}
ペイロードの中身は誰でも簡単に見れるので、パスワードなどの機密情報は入れてはいけません。
サーバーは生成したJWTをクライアントに返します。
HTTP/1.1 200 OK
Content-Type: application/json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
2. クライアントでJWTを保存する
クライアント(ブラウザやアプリ)は、受け取ったJWTを保存します。
保存場所としては次の2つが一般的です。
1. ローカルストレージ
- メリット: 簡単に扱える
- デメリット: XSS(クロスサイトスクリプティング)攻撃のリスクがある
2. Cookie
- メリット: Secure属性やHttpOnly属性を付けることでセキュリティを強化できる
- デメリット: CSRF(クロスサイトリクエストフォージェリ)攻撃への対策が必要
3. 認証が必要なリクエスト時にJWTを送る
クライアントはサーバーにリクエストを送る際、JWTをHTTPヘッダーに含めます。
GET /api/user/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
このとき、JWTはAuthorizationヘッダーのBearerトークンとして送信されます。
4. サーバー側でJWTを検証する
サーバーは受け取ったJWTを以下の手順で検証します。
1. 署名の検証
JWTの署名部分(Signature)を確認し、トークンが改ざんされていないかをチェックします。
2. 有効期限の確認
ペイロードのexp(有効期限)フィールドを見て、トークンが期限切れでないかを確認します。
3. ペイロードの確認
必要に応じて、ペイロード内のデータ(ユーザーIDなど)を使って追加の処理を行います。
検証が成功すれば、サーバーはリクエストを許可し、必要なデータを返します。
検証が失敗したらサーバーは401エラーを返します。
JWT認証のメリット
- ステートレス:サーバーが状態を管理しないため、スケーラビリティが高い。
- 軽量:JSONベースで、どんな環境でも扱いやすい。
- 汎用性:API間のデータ共有や分散システムでも利用可能。
注意点
ペイロードは暗号化されない
→ 中身を見られても問題ないデータだけを含めましょう。
トークンの有効期限を設定する
→ トークンが無期限だとセキュリティリスクが高まります。
参考
Discussion