「デバイスを跨いでもログイン状態を維持したい」という要件があるとき、セッション情報(JWT やセッション ID)をどこに保存するのがベストなのか。 localStorage、sessionStorage、Cookie... それぞれの選択肢にはメリットとデメリットがありますが、セキュリティと運用性を考えると、実は「正解」は絞られてきます。

4 つの代表的な選択肢を比較しながら、なぜその方法が推奨されるのかを深掘りします。

比較する 4 つの選択肢

A) localStorage に保存された JWT

  • 永続性:◯(ブラウザを閉じても保持される)
  • リスクXSS(クロスサイトスクリプティング)に極めて弱い
  • 結論:JavaScript から中身が丸見えなので、悪意のあるスクリプトが実行された瞬間にトークンを盗まれます。セキュリティを重視するなら推奨されません。

B) httpOnly クッキーに保存された JWT

  • 永続性:◯(Cookie の有効期限内なら保持される)
  • リスク:JavaScript からアクセスできない(httpOnly)ため、XSS 耐性がある。
  • 課題
    • JWT はサーバー側で状態を持たないため、「特定のデバイスだけ強制ログアウトさせる」といった制御が難しい。
    • トークンの失効管理(ブラックリスト管理)を始めると、ステートレスという JWT の利点が薄れてしまう。

C) httpOnly クッキーに保存された「セッション ID」(最適解)

  • 永続性:◯
  • セキュリティ:◯(httpOnly により XSS 耐性があり、Secure 属性で HTTPS 通信のみに限定可能)
  • 運用の柔軟性◎ 最も柔軟
    • 実体はサーバー側の Redis や DB にあるため、サーバー側でセッションを自由に無効化できる。
    • 「ログイン中のデバイス一覧」を表示したり、パスワード変更時にすべてのセッションを破棄したりする処理が容易。

D) sessionStorage に保存された JWT

  • 永続性:✕(タブを閉じると消える)
  • 要件への適合:今回の「デバイス間で永続させたい」という要件には全く適合しません。

なぜ「httpOnly クッキー + セッション ID」が選ばれるのか

現代のウェブ開発において、特にセキュリティと高度なユーザー管理が必要な場合、**選択肢 C(httpOnly クッキー + サーバー管理のセッション ID)**が最もバランスが良いとされています。

  1. XSS 対策:httpOnly 属性により、万が一スクリプトが混入してもセッション ID は盗まれません。
  2. サーバー側での制御権:JWT のような「一度発行したら止められない」というリスクがなく、サーバー側でいつでもアクセス権を取り消せます。
  3. デバイス管理:ユーザーが複数のデバイスでログインしている場合、それぞれのセッションを個別に管理(表示・削除)できるのは、サーバー側で状態を持っている強みです。

まとめ

「スケーラビリティのために JWT を localStorage に」という誘惑は多いですが、セキュリティ事故のリスクや、後から「特定のユーザーを強制ログアウトさせたい」となった時の困り具合を考えると、Cookie とサーバーサイドセッションの組み合わせが、今でも最も堅実で安全な選択肢と言えます。