そもそもログイン機能とは
まず、ログインとはインターネット上のサービスを利用する際に、IDとパスワードを使って本人を確認する仕組みのことです。
そしてログインには認証と認可という2つのプロセスがあります。
- 認証 (Authentication):その人が本人であることを確認する(例:IDとパスワード)
- 認可 (Authorization):その人が何をしてよいかを決める(例:有料会員だけに有料コンテンツを閲覧できる)
なぜログイン機能が必要か?
もしAmazonにログインがなければ、毎回注文のたびに住所、氏名、支払い方法などを入力しないといけなくなりますし、もしTwitterにログインがなければ、他人になりすましての発言が容易にできてしまう。
なので、個人に紐付くデータを扱うサービスにはログインの仕組みが必要なのです。
HTTP通信はステートレス
HTTP/HTTPS通信は、毎回独立しています。
静的サイトしかない時代はよかったのですが、昨今のログインが必要なサービスなどでは、クライアントからサーバーへ毎回ID、PWを送らないといけなくなります。
しかし、それは大変なので、この問題を解決する為にCookieが生まれました。
*Cookieの正式名称はHTTP Cookie
ざっくり言うとサーバーは認証ができたクライアントに対して鍵を渡し、クライアントは以後サーバーとの通信時に、毎回その鍵を渡せば相互で識別できるようになり、ステートフルになる。その鍵、身分証の様な役目をしているのがCookieです。
Cookieをさらに詳しく
Cookieとは?
WEBサイトがユーザーのブラウザに保存する小さなデータのこと。
利用するサイトのWebサーバーが発行し、ブラウザのStorageのCookiesに保管される。
Cookieの目的
- 状態の保持
ログイン状態や、ショッピングカートの中身などユーザーの状態保持に使われる。 - トラッキング
ユーザーの行動を追跡し、広告の最適化、サイトの改善に活用される。
例えばECサイトで商品を買い物カゴに入れてからWebサイトを閉じても、再訪問時に買い物カゴに商品が入っているという経験が誰でもあると思います。また、SNSなどのサイトにログインして、一定期間ログイン状態が保持される。
これらは皆Cookieのおかげなのです。
ブラウザの中に情報を保存するという点で、ローカルストレージとの違いは?
Cookieとローカルストレージでは結果としてできることはほぼ同じです。
しかしローカルストレージとCookieでは情報の保存期間とデータ容量に差があります。ローカルストレージであれば半永久的に保存できますが、Cookieの場合は保存期間が制限されます。
またデータ容量においてもローカルストレージが5 MBなのに対し、クッキーは4 KBしかありません。またCookieの場合、通信を行うたびにデータ送信を行っているため、Cookieの情報が多ければ多いほど、重くなるという問題があります。
| 項目 | Cookie | Local Storage |
|---|---|---|
| 保存容量 | 約4KB | 約5MB |
| 有効期限 | サーバー指定orセッション | 半永久(手動で削除しない限り) |
| 自動送信 | ✅ HTTPリクエストに含まれる | ❌ 手動で取得・送信 |
| JSからアクセス | ✅ ただしHttpOnlyなら不可 | ✅ 可能 |
| セキュリティ | CSRFに弱い(SameSiteで対策) | XSSに弱い |
余談ですが、Cookieという言葉が指す範囲は広い。
サーバーから付与されるファイルの意味で使われたり、
ブラウザのStorageにCookiesという場所があるので保管庫みたいな表現だったり、
仕組みのことだったり、
と広いのですが、臨機応変に解釈しましょう。
2つの主要な認証方式
HTTP通信の認証は、以下の2つが主に使われています。
- セッション/Cookieベース
- トークンベース
1. セッション/Cookieベース:サーバーで認証状態を保持
セッションは本来Cookieをもとに成り立っている仕組みなので、両方の呼び名が混在。
流れ:
- フロントがログイン情報(ID・パスワード)を送信
- サーバーが認証に成功すると、Cookie(ログイン情報等を含んだセッションID)を生成し、DBに保存
- CookieをHTTPレスポンスのヘッダを利用してフロントに送る
- フロントはブラウザのCookieに保管
- 以降のリクエストでブラウザが勝手にCookie(セッションID)をリクエストヘッダーにつけてリクエストしてくれる
- サーバー側では自身で持っているセッションIDと合致するかをみて、認証
- そのセッションIDを使って、保存されたユーザー情報を参照し、リクエストを処理
*サーバー側はセッションIDが誰に対して発行したものかをわかっています。
*一度Cookieをセットすると、ブラウザが以後のリクエストで自動的にCookieを送信してくれるので、開発者がリクエストごとに認証情報を明示的に設定する必要がない。
また、Cookieにはセキュリティのための様々な属性がある
- 決まったドメインにしか送れないDomain属性
- JavaScriptで触れなくするHTTP Only属性
など
2. トークンベース:フロントで認証状態を保持
- フロントがログイン情報(ID・パスワード)を送信
- サーバーが認証に成功すると、トークン(例:JWT)を生成してレスポンス
(*トークンにはユーザーIDや有効期限などの情報が含まれる) - フロントが受け取ったトークンを保存
保存先は LocalStorage や SessionStorage、または Cookie(HttpOnly推奨) - 以後のリクエストで、フロントはトークンを Authorization: Bearer ヘッダーに含めて送信
- サーバーがトークンを受け取り、署名を検証
(*改ざんされていないか、期限切れでないかなどを確認) - トークンのペイロードを読み取り、ユーザー情報を取得
- 必要に応じて、ユーザーの権限やロールをチェックし、リクエストを処理
トークンは、アプリ内での滞在許可、ビザのようなもので、有効期間があり、切れると再ログインがいる。(それにはリフレッシュトークンというものを使う)
銀行、証券など金融サービスはこのトークンの有効期間は短く、厳しい。
トークンの保管場所:
- LocalStorage:XSSに弱く、悪意のあるスクリプト注入で盗まれるリスクがある
- Cookie:一般的だが、XSS、CSRF(クロスサイトリクエストフォージェリ)に弱い
- HttpOnly Cookie:HttpOnly属性を付けることで、JavaScriptからのアクセスが禁止なのでXSSから守れる。サーバーが Set-Cookie ヘッダーで設定し、以後のリクエストに自動的に含まれる。
保管場所の例:
-
A社 (AWS Amplify、Cognitoを使っている)
ログインのタイミングでJWTをCookieなどに保管してない。
APIリクエスト時にtokenをAmplifyの機能でfetchして、ヘッダーにtokenをつける -
B社
ログインした時にJWTをNookiesというライブラリでCookieに保管
APIリクエスト時にCookieに保管したトークンを取り出してヘッダーにつける -
C社
ログインした時にJWTをStoreに保管
APIリクエスト時、Storeに保管したトークンを取り出してヘッダーにつける
JWT
JSON Web Tokenの略で、ジョットと読む。
暗号化されたJSONで記載されたフォーマットのトークンによる認証方式のひとつ。
スケーラビリティ、スマホアプリ、SPAでの扱いやすさの理由でこのJWTによるトークン認証が主流になってきている。
ヘッダー、ペイロード、署名の3部構成
{
"header": { "alg": "HS256", "typ": "JWT" },
"payload": { "sub": "user123", "exp": 1720000000 },
"signature": "..."
}
「セッション/Cookieベース」と「トークンベース」の違い
セッション/Cookieベース認証
- サーバーがセッションIDを保持
- サーバーはセッションIDに紐づけて、ユーザー情報をメモリやDBに保存
つまり、状態をサーバー側で管理するステートフル な方式
トークンベース認証
- サーバーはトークンを保持しない(ただし、ブラックリストなどを使う場合は例外)
- サーバーはクライアントから送られたトークンを検証(署名の確認、有効期限、クレームなど)し、ユーザー情報をトークンから直接取得
(*トークン自体にユーザー情報が含まれる)
つまり、状態をクライアント側で保持するステートレス な方式
セッション/Cookieベース認証がステートフルな通信を実現できるというメリットを持つ一方で、トークンベース認証は (サーバーに認証のための情報を持つ必要がないため) ユーザーが増加した時のサーバー負荷がセッションベース認証よりも少なく、よりスケーラブルなシステムを実現できるというメリットを持ちます。
セッション、トークンの無効になるタイミング:
- セッション認証ならログアウトで無効になる
- トークンは普通にログアウトしても無効にならないので、そのtokenを盗まれると悪用される危険がある
ログアウトしてJWTを無効にする実装が必要
まとめ
完全なログイン認証はまだなく、脆弱性はある、スタンダードもまだない状態ですが、今まで関わったプロジェクトは全てJWTによるトークン認証だったのでこれが主流なのかなと思います。

