一般的なJWT認証とフロントエンドでの認証方法まとめ
一般的なJWT認証とフロントエンドでの認証方法まとめ

一般的なJWT認証とフロントエンドでの認証方法まとめ

特定のフレームワークやデータベースに依存しない、一般的な「JWT(JSON Web Token)認証」の仕組みと、フロントエンド(ブラウザ側)でその認証情報をどう扱うべきかについてまとめました。

Supabaseなどを利用する際に、普段は何となくコピペで済ませてしまいがちな部分ですが、仕組みを理解していた方が、エンジニアとしてステップアップすることができますし、理解していた方が応用もしやすいです。

1. JWT認証の全体的な流れ

JWT認証は、遊園地の「入場チケット」のような仕組みで成り立っています。

バックエンドがセッション状態(誰がログインしているか)をサーバー側で保持しなくて済む「ステートレス」な特性であり、現代のWeb開発で広く使われています。

JWTの構造

JWTは以下の3つのパーツがドット(.)で連結された文字列です。

ヘッダー.ペイロード.署名
  • ヘッダー: 署名アルゴリズム(例:HS256)とトークンタイプを指定
  • ペイロード: ユーザーIDや権限、有効期限(exp)などの情報(クレーム)
  • 署名: 「ヘッダー + ペイロード」をサーバーの秘密鍵でハッシュ化したもの。これにより内容の改ざんを検知できます。

① 発行(ログイン時)

1. ユーザーがフロントエンドからIDとパスワードを送信します。

2. 認証サーバーが情報を確認し、正しい場合は「このチケットの持ち主は〇〇さんです」という情報と「電子署名(改ざん検知のための署名)」を含んだJWT(トークン)を発行して返します。

② 提示(API利用時)

1. ユーザーがマイページを開くなどの操作をする際、フロントエンドはバックエンドAPIに対してリクエストを送ります。

2. この時、リクエストの「ヘッダー(通信の付加情報)」に、以下の形式でJWTをセットして送信します。

Authorization: Bearer <token>

③ 検証(API側)

1. バックエンドAPIは、送られてきたJWTの「電子署名」を検証します。

2. 署名が正しく、有効期限内であれば「本物のチケット」とみなし、要求されたデータを返します。

3. 偽造されたり期限切れの場合は、エラーを返してアクセスを拒否します。

2. フロントエンドでの認証方法(トークンの保存場所)

バックエンドから受け取った大切なJWTを、フロントエンド(ブラウザ)のどこに保存するかは、セキュリティ上非常に重要なテーマです。大きく分けて2つの主流な方法があります。

パターンA:Web Storage (LocalStorage / SessionStorage) に保存する

ブラウザに備わっている、データを手軽に保存できる領域にトークンを置く方法です。

  • メリット: 実装が非常にシンプルで簡単です。APIにリクエストを送る際、JavaScriptで簡単に取り出してヘッダーにセットできます。
  • デメリット(セキュリティリスク): XSS(クロスサイトスクリプティング)攻撃に弱いです。もし悪意のあるJavaScriptがあなたのサイト上で実行されてしまった場合、LocalStorageの中身(大切なトークン)は簡単に盗み出されてしまいます。

パターンB:HttpOnly Cookie に保存する

ブラウザの「Cookie」という仕組みを使い、さらにJavaScriptからは読み取れない「HttpOnly」という鍵をかけて保存する方法です。現代のセキュアなアプリケーションではこちらが推奨されることが多いです。

  • メリット: XSS攻撃に強いです。JavaScriptからアクセスできないため、万が一悪意のあるスクリプトが実行されてもトークンを盗まれません。設定しておけば、APIへリクエストを送る際にブラウザが自動的にCookieを送信してくれるため、フロントエンドのコードが少し楽になります。
  • デメリット: CSRF(クロスサイトリクエストフォージェリ)攻撃の対策が必要になります。別の悪意あるサイトから、ユーザーの意図しないリクエストを勝手に送られてしまうリスクがあるため、CookieにSameSite=StrictまたはSameSite=Lax属性を付けてリスクを緩和しつつ、CSRFトークンと組み合わせた多層防御が推奨されます。バックエンド側でCookieを発行・読み取る設定(CORS設定など)が少し複雑になります。

3. まとめ:どう設計すべきか?

特定のサービス(HonoやSupabaseなど)を使わなくても、認証の基本設計は以下のようになります。

1. バックエンドの役割: トークンの「署名」が正しいかを毎回しっかり検証すること。どの言語・フレームワークを使ってもこのロジックは変わりません。

2. フロントエンドの役割: 受け取ったトークンを安全に保管し、API通信のたびに提示すること。アクセストークンの有効期限(exp)は短く(15〜60分程度)設定し、期限切れ後はリフレッシュトークンを使って新しいアクセストークンを取得する「トークンリフレッシュ」の設計が一般的です。

3. 保存場所の選択:

  • ・セキュリティ要件が非常に厳しい場合や、金融系などのアプリケーションではHttpOnly Cookieが推奨されます。
  • ・個人開発や、比較的リスクが低いアプリケーション、あるいは完全にフロントエンドとバックエンドが分離されたSPA環境などでは、実装の手軽さからLocalStorageが選ばれることも多いですが、XSS対策(Reactなどのモダンフレームワークの標準機能でエスケープするなど)は必須です。

このように、JWT認証の仕組みを概念として理解しておけば、今後どのような技術スタックを選んだとしても応用が利きます。

関連記事