SPAで認証が複雑化する理由とトークン更新問題

SPAで認証実装が複雑化する理由とトークンリフレッシュ問題

SPAのログイン実装は、見た目以上に設計難易度が高いです。フォーム送信とCookieだけで成立していた従来のWebアプリと違い、SPAでは「ログイン状態をどこに保持するか」自体を設計しなければならないためです。

特に多くの開発者がつまずくのが、アクセストークンとリフレッシュトークンの扱いです。これは単なるライブラリ設定の話ではなく、ブラウザのセキュリティモデルに直接関係しています。

なぜSPAはセッション認証をそのまま使えないのか

従来のWebアプリでは、ログインするとセッションCookieが保存され、以降のリクエストには自動的にCookieが送信されます。開発者は認証を意識せずに画面を作れました。

SPAでは事情が変わります。SPAはAPIサーバと分離される構成が多く、次の形になります。

  • フロントエンド(example.com)
  • API(api.example.com)

このときブラウザはクロスオリジン通信として扱います。Cookieは自動送信されません。CORS設定やSameSite属性の影響を受けるため、従来のセッション認証が不安定になります。

そのためSPAではトークン認証が採用されることが増えました。

アクセストークンとは何か

ログイン成功時、サーバはユーザーを証明する短命のトークンを発行します。

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

フロントエンドはAPI呼び出し時にヘッダへ付与します。

Authorization: Bearer eyJhbGciOi...

これによりサーバはユーザーを認識します。

ここまではシンプルですが、問題は有効期限です。

なぜトークンは短命にする必要があるのか

トークンは「持っている人が本人」とみなされます。つまり盗まれた場合、完全に乗っ取られます。Cookieならサーバ側で失効できますが、署名付きトークンは基本的に無効化が困難です。

そのためアクセストークンは数分〜数十分で期限切れにします。

ここで問題が発生します。

トークンリフレッシュ問題

期限が切れたトークンを使ってAPIを呼ぶと、401 Unauthorizedが返ります。

HTTP/1.1 401 Unauthorized

ユーザーはログアウトしたわけではありませんが、アプリは認証失敗として扱います。何もしないと、操作中に突然ログイン画面へ戻る挙動になります。

これを防ぐため、リフレッシュトークンを使います。

リフレッシュトークンの役割

リフレッシュトークンは長寿命の再発行用トークンです。アクセストークンが失効したとき、新しいトークンを取得します。

if (response.status === 401) {
  await refreshToken();
  retryRequest();
}

一見簡単に見えますが、実装には複数の落とし穴があります。

同時リクエスト問題

SPAでは画面表示時に複数APIを同時に呼びます。トークン期限切れの場合、すべてのリクエストが同時に401になります。

結果として、同時に複数のリフレッシュ処理が走ります。

  • トークン再発行が競合
  • 古いトークンで再試行
  • 無限リトライ

これが「ランダムにログアウトする」現象の原因になります。リフレッシュ処理は排他制御が必要です。

トークンの保存場所問題

次に重要なのが保存場所です。

候補は主に2つあります。

  • localStorage
  • Cookie

localStorageは扱いやすいですが、XSSに弱いです。スクリプトが実行されるとトークンを盗まれます。

一方、HttpOnly CookieはJavaScriptから読めないため安全ですが、CSRF対策が必要になります。どちらも完全ではありません。

よくある危険な実装

実務で多い失敗があります。

  • アクセストークンをlocalStorage保存
  • 有効期限を長期間に設定
  • リフレッシュトークンも同じ場所に保存

これはセッション固定攻撃やXSSの被害を大きくします。攻撃者にとっては「ログイン状態を永続的に盗める」状態になります。

なぜSPAだけ問題になるのか

MPAではブラウザが自動的にCookieを送信し、セッション更新もサーバが行っていました。フロントエンドは認証の存在を意識しませんでした。

SPAでは、認証制御の一部をクライアントが担います。つまり「セキュリティの責任の一部がJavaScriptに移る」ことになります。これが難しさの本質です。

対策の考え方

実務では次の構成が比較的安定します。

  • アクセストークン:短命
  • リフレッシュトークン:HttpOnly Cookie
  • 自動再取得:排他制御付き

これによりXSSとCSRFのリスクバランスを取れます。

まとめ

SPAで認証が複雑化する理由は、トークン技術が難しいからではありません。ブラウザが従来担っていたセッション管理を、アプリケーションが実装する必要があるためです。

トークンリフレッシュは「ログインを維持する仕組み」ではなく、「盗まれても被害を限定する仕組み」です。この視点で設計すると、保存場所や期限の意味が理解しやすくなります。

ログイン機構は後付けすると必ず破綻します。SPAでは画面設計と同時に認証フローを設計することが、最も重要な安定化ポイントになります。