0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JWT(JSON Web Token)学習メモ

Last updated at Posted at 2025-07-07

JWT(JSON Web Token)徹底解説:構造から実務での活用法まで

こんにちは!Web開発の世界でよく耳にする「JWT」、皆さんはどれくらい理解されていますか?本記事では、JWTの基本的な構造から、なぜ使われるのか、そして実務でどのように活用されているのかを、分かりやすく解説していきます。

1. JWTの基本的な構造

JWTは、大きく分けて以下の3つの部分から構成されます。これらはドット (.) で区切られています。

<Header>.<Payload>.<Signature>

1.1. Header(ヘッダー)

  • 役割: どのようなアルゴリズムでSignatureが生成されたか、トークンのタイプなどを定義します。
  • :
    {
      "alg": "HS256",  // 使用する署名アルゴリズム (HS256, RS256など)
      "typ": "JWT"     // トークンのタイプ (通常"JWT"で固定)
    }
    
  • 補足: alg には HMAC SHA256 (HS256) や RSA SHA256 (RS256) などが指定されます。

1.2. Payload(ペイロード)

  • 役割: トークンに含まれる情報(クレーム)を格納します。これは暗号化されておらず、誰でも内容を確認できますが、改ざんはできません(Signatureによって保証)。
  • :
    {
      "sub": "user123",    // ユーザーID (subject)
      "iat": 1716700000,   // 発行日時 (issued at)
      "exp": 1716703600    // 有効期限 (expiration time)
    }
    
  • 補足: sub はユーザー識別子、iat は発行時刻、exp は有効期限を表す代表的なクレームです。ここにユーザーのロールや権限などの情報を追加することも可能です。

1.3. Signature(署名)

  • 役割: HeaderとPayloadを結合し、Headerで指定されたアルゴリズムとサーバーの秘密鍵(または公開鍵)を使って生成されます。この署名によって、トークンが改ざんされていないことを証明します。
  • 生成方法:
    Signature = HMACSHA256(
        base64UrlEncode(Header) + "." + base64UrlEncode(Payload),
        secret
    )
    
  • 補足: Payloadの内容が少しでも変更されると、Signatureが無効になります。これがJWTの「誰でも見れるけど、改ざんは不可能」という性質を担保しています。

2. JWTのメリット(なぜ使われるのか?)

JWTが広く利用されるには、いくつかの優れた特徴があります。

2.1. Statelessness(ステートレス性)

  • セッションベースの認証と異なり、サーバー側でセッション情報を保持する必要がありません。これにより、データベースへのアクセスが減り、システムのスケーラビリティが向上します。

2.2. Cross-domain and Cross-service(ドメイン間・サービス間の連携)

  • 一つのサービスで発行されたJWTを、他のサービスでも検証できます。これはマイクロサービスアーキテクチャとの相性が非常に良いです。

2.3. Compactness(コンパクトさ)

  • エンコードされた形式(Base64Urlエンコード)により、HTTPヘッダーやURLパラメータなどで効率的に送信できます。

2.4. Self-contained(自己完結性)

  • 必要な情報(ユーザーID、有効期限など)がトークン自体に含まれているため、認証処理に追加のデータベース 조회が不要な場合があります。

3. JWTは無人택배함!?〜ステートレスの例え〜

ここで、JWTのステートレスな性質を分かりやすく例えてみましょう。

【セッションベースの認証: 경비실(警備室)に預ける】

  • あなたが荷物を注文し、不在でした。
  • 配達員は「警備室に預けてください」と依頼し、警備員は荷物リストにあなたの名前を記録します。
  • 後で荷物を受け取りに行く際、「〇〇号室の〇〇です」と伝えると、警備員は記録を確認し荷物を渡してくれます。
  • 問題点: 警備員がいない、または荷物が多すぎると、受け取れない(サーバー依存、サーバー負荷)。

【JWT: 無人택배함に預ける】

  • あなたが不在でも、配達員は荷物を「無人택배함」に保管します。
  • 保管後、あなたは「QRコード」を受け取ります。
  • あなたはいつでも無人택배함に行き、QRコードをかざすだけで荷物を受け取れます。
  • 利点: 警備員(サーバー)の都合に左右されず、いつでも自分で受け取れます。また、一度渡したQRコード(JWT)は、受け取る側(クライアント)が管理します。

このように、JWTは「受け取った人が自分で管理・提示する情報」という点で、無人택배함に例えることができます。

4. JWTはいつ使うべきか?

どのような状況でJWTが適しているのでしょうか?

  1. サーバーがステートレスで運用される場合: セッションストアなしで、JWTのみを見て認証処理を行う必要がある時。
  2. マイクロサービスアーキテクチャ: Aサービスでログインしたユーザーが、BやCサービスでも同じJWTで認証される必要がある場合。
  3. HTTPベースのAPI通信のみの場合: WebアプリケーションのAPI認証など。
  4. 複数のドメイン/サービス間で、単一のログインで認証を維持したい場合

5. io.jsonwebtoken (jjwt)ライブラリの必要性

JavaやSpring BootでJWTを扱う際、io.jsonwebtoken(通称 jjwt)のようなライブラリはなぜ必要なのでしょうか?

  • 結論: JWTを直接生成・検証するにはライブラリが必須だからです。
  • 理由:
    • JWTの生成、署名、検証、クレームの抽出などを簡単に行うためにJWTライブラリが必要になります。
  • 代替案:
    1. Spring Security + OAuth2: Spring Securityが提供するJWT機能を活用することも可能ですが、設定が複雑になる場合があります。
    2. 直接実装: Base64エンコードや署名処理などを自前で実装することも理論上可能ですが、セキュリティ上の脆弱性を生むリスクが非常に高いため、非推奨です。
  • 補足: jjwt 以外にも、auth0/java-jwtNimbus JOSE + JWT といったライブラリもよく利用されます。

6. コントローラーメソッドの引数名が認識されないエラーとその解決策

Spring MVCで @RequestParam@PathVariable を使う際、稀に引数名が認識されずエラーが発生することがあります。

  • 原因: コンパイル時に -parameters オプションなしでビルドされた場合、クラスファイルに引数名情報が含まれなくなるためです。
  • : public String getToken(String username) のように引数名を省略した場合、Springが username という名前を特定できなくなります。
  • 解決策:
    1. 引数に明示的にアノテーションで名前を指定する:
      @GetMapping("/token")
      public String getToken(@RequestParam("username") String username) {
          // ...
      }
      
    2. コンパイル時のオプション設定: ビルドツール(Maven/Gradle)で -parameters オプションを有効にする。

明示的に指定する方が、コードの意図が明確になり、より安全です。

7. Postmanを使ったJWTのやり取り(イメージ)

PostmanはJWTを使ったAPIテストに非常に便利です。

  • ログインAPI: ID/パスワードを送信し、成功するとAuthorization: Bearer <JWT> という形式でレスポンスヘッダーにJWTが返ってくることが多いです。また、レスポンスボディにもJSON形式でトークンが含まれる場合もあります。
  • 認証が必要なAPI: 前のAPIで取得したJWTを、Authorization: Bearer <JWT> の形式でリクエストヘッダーに含めて送信します。

8. HS256アルゴリズムとは?

HS256 はJWTで最も一般的に使用される署名アルゴリズムの一つです。

  • HS256: HMAC (Hash-based Message Authentication Code) に SHA-256 ハッシュ関数を組み合わせたものです。
  • 仕組み: 秘密鍵(共通鍵)を用いて、ヘッダーとペイロードの結合文字列をハッシュ化し、署名を生成します。サーバーとクライアント(または異なるサービス間)で同じ秘密鍵を共有することで署名の検証が可能になります。
  • : Keys.secretKeyFor(SignatureAlgorithm.HS256) のように、ライブラリで秘密鍵を生成します。この秘密鍵は絶対に漏洩させてはなりません。

9. URL末尾の改行文字 (\n) による404エラー

PostmanでAPIを呼び出す際、URLの最後に意図せず改行文字 (\n) が含まれていると、Spring MVCがパスを見つけられずに404エラーを返すことがあります。

  • 原因: Springはパスとして /check\n というリソースを探しに行きますが、実際には /check というパスしか存在しないためです。
  • 解決策: PostmanのURL入力欄の末尾に余分な改行やスペースが含まれていないか確認し、削除してから再試行してください。

10. JWTはサーバーで「削除」できない理由

JWTはステートレスであるため、サーバー側で直接「削除」することはできません

  • 理由:
    • JWTはサーバーに保存されず、クライアント(ブラウザのLocalStorageやCookieなど)に保管されます。
    • サーバーは受け取ったJWTの有効性(署名の検証や有効期限)を確認するだけで、そのJWTの存在自体を管理しているわけではありません。
  • 【対策】トークンの無効化(ログインアウト):
    1. 有効期限を短く設定する: 例えば15分〜1時間程度にし、その都度再ログインまたはリフレッシュトークンで更新する。
    2. ブラックリスト(失効リスト)の管理: ログアウト時に、そのJWTのID(jtiクレームなど)をサーバー側のデータベースやRedisに保存し、リクエストごとにブラックリストに含まれていないか確認する。
    3. リフレッシュトークンとの併用: アクセストークン(短命)とリフレッシュトークン(長命)を使い分け、リフレッシュトークンはサーバー側で管理する。

11. トークンの渡し方:Authorization: Bearer <token>

クライアントからサーバーへJWTを渡す際の標準的な方法は、HTTPヘッダーの Authorization を使うことです。

  • 形式: Authorization: Bearer <access_token>
  • Bearer の意味: これはRFC 6750で定義されている認証スキームの一つで、「このトークン(Bearer Token)を持っている人が認証されますよ」という意味を表します。
  • なぜ必要か:
    • サーバーが受け取ったトークンが、どのような種類の認証情報なのかを明確にするためです。Bearer が付いていることで、サーバーはそれをJWTアクセストークンとして解釈します。
    • これがないと、サーバーは認証ヘッダーを適切に処理できず、認証エラーとなる可能性があります。
  • 他の認証方式の例: Authorization: Basic <base64encoded_id:password> など。

12. ResponseEntity を使ったトークンの返却方法

Spring Bootのレスポンスで、ヘッダーとボディの両方にトークンを含めるのは一般的な方法です。

return ResponseEntity
    .status(HttpStatus.OK)
    .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) // 🔹 トークンをレスポンスヘッダーに含める
    .body(Map.of("token", token));                         // 🔹 同時にレスポンスボディにも含める


メリット:

ヘッダー: クライアント側で response.headers.get("Authorization") のようにして取得でき標準的な認証ヘッダーとして扱われます

ボディ: JavaScriptのFetch APIやAxiosなどで response.data.token のようにJSONから直接取り出して扱いやすいです

この方法はクライアント側がどちらの方法でトークンを受け取っても対応できるため汎用性が高いです

13. JWT認証の典型的なシナリオ

一般的なWebアプリケーションでのJWT認証フローは以下のようになります

ログイン: ユーザーがID/パスワードをフォームで送信します

認証: バックエンドは送信された認証情報を検証します

JWT発行: 認証成功後バックエンドはJWTを生成しクライアントに返却しますヘッダーボディなど)。

トークン保存: クライアントは受け取ったJWTを保存しますLocalStorage, SessionStorage, HttpOnly Cookieなど)。

APIリクエスト: 以降の認証が必要なAPIリクエストでは保存したJWTを Authorization: Bearer <JWT> ヘッダーに含めて送信します

トークン検証: バックエンドはリクエストヘッダーからJWTを抽出し署名や有効期限を検証します

認可: 検証が通ればそのJWTに含まれる情報ユーザーIDやロールなどに基づいてリクエストされた操作を許可するかどうか認可を判断します

この流れのポイントは**サーバー側がJWTの状態を管理しないステートレス**点です

クライアント側でのトークン保存場所の選択肢

LocalStorage: JavaScriptからアクセス可能XSS攻撃に弱い

SessionStorage: ブラウザタブを閉じると消えるXSS攻撃に弱い

HttpOnly Cookie: JavaScriptからアクセス不可XSS攻撃に強くセキュリティが高い

14. JWTの内容を暗号化したい場合JWEJSON Web Encryption

標準的なJWTJWS: JSON Web Signature内容がBase64エンコードされているだけで誰でもデコードして中身を見ることができます

JWE: JSON Web Encryptionの略でJWTのペイロード部分を暗号化する仕組みです

JWS vs JWE:

JWS: データの改ざん防止署名のみ)。内容は平文

JWE: データの機密性保護ペイロードを暗号化)。内容は秘匿

使い分け:

ユーザーIDや有効期限のような機密性がそれほど高くない情報であればJWSで十分です

JWT内に個人情報や非常に機密性の高い情報をどうしても含めたい場合はJWEの利用を検討します

実務では: 通常はJWSで十分ですがサービス要件に応じてJWEや秘密鍵を安全に管理した上でJWTを併用するなどの工夫がされます

15. JWTの限界と実務での組み合わせ

JWT単独で利用するにはいくつかの限界があります

JWTの主な限界

トークン無効化の難しさ: 一度発行されたJWTは有効期限内であればサーバー側から強制的に無効化できません削除できない)。

細やかな権限管理の難しさ: JWT内にロール情報を入れても複雑な条件付きの認可処理はコードが煩雑になりがちです

トークン漏洩のリスク: クライアント側で管理されるためXSSなどの攻撃でトークンが漏洩すると有効期限内は不正利用されます

リフレッシュ不可: アクセストークンのみの場合有効期限が切れると再ログインが必要になりユーザー体験が悪くなります

実務での標準的な組み合わせ

これらの限界を克服するため実務では以下のような組み合わせが一般的です

Access Token (短い有効期限): ユーザー認証情報を含み各APIリクエストに使用

Refresh Token (長い有効期限): Access Tokenの再発行に使用このリフレッシュトークンはサーバー側でRedisなどのキャッシュに管理します

Redisなどのキャッシュストア: リフレッシュトークンの保存ブラックリスト管理に使用

Spring Security: 認証認可処理全体のフレームワークとして機能

Token無効化の仕組み

Access Tokenはステートレスに扱いますがリフレッシュトークンはサーバー側Redisなどで管理します

ログアウト時にはRedisからリフレッシュトークンを削除したりAccess Tokenをブラックリストに追加したりすることで事実上のトークン無効化を実現します

このようにSpring SecurityとJWTそしてリフレッシュトークンとRedisを組み合わせることで堅牢でスケーラブルな認証システムを構築するのが一般的です

まとめ

JWTはステートレスな認証を実現しスケーラビリティやサービス間連携に優れた強力なツールですしかしその特性上トークンの無効化やセキュリティリスクへの対応にはリフレッシュトークンやサーバー側での管理といった他の技術との組み合わせが不可欠です
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?