JWTの基礎
JWTが何のためのトークンなのか、Bearer認証でどう使われるのかをAPI実装前に理解する
JWTとは
JWT(JSON Web Token)は、ログイン後のユーザー情報や権限などを 署名付きの文字列 として表現するための仕様。
NestJSやNext.js固有のものではなく、Web API全般で使われる認証・認可まわりの仕組み。
よくある使い方は次の流れ。
1. ユーザーがメールアドレスとパスワードでログインする
2. サーバーが認証に成功したらJWTを発行する
3. クライアントは以後のAPIリクエストにJWTを付けて送る
4. サーバーはJWTを検証し、誰のリクエストか判断するAPIではどう送るか
REST APIでは、HTTPヘッダーの Authorization に入れて送ることが多い。
GET /users/me
Authorization: Bearer xxxxx.yyyyy.zzzzzこの Bearer は「このトークンを持っている人として扱ってください」という意味合い。
JWT認証の記事で出てくる Authorization: Bearer <accessToken> はこの形。
JWTの中身
JWTは、見た目としてはドット区切りの3パートになっている。
header.payload.signature- header … 署名アルゴリズムなどの情報
- payload … ユーザーIDやメールアドレスなど、アプリ側が使いたい情報
- signature … 改ざんされていないことを確認するための署名
たとえばpayloadには次のような情報を入れることがある。
{
"sub": "user_id_123",
"email": "taro@example.com",
"iat": 1710000000,
"exp": 1710003600
}sub はsubjectの略で「このトークンの主体」を表す。ユーザー認証ではユーザーIDを入れることが多い。
exp は有効期限。期限切れのJWTは拒否する。
署名は「暗号化」ではない
ここは重要。
JWTは署名されているが、基本的には 暗号化されているわけではない。
JWTのpayloadは、ツールを使えば中身を読める。
つまり、payloadには次のような情報を入れない。
- パスワード
- クレジットカード番号
- 個人情報の詳細
- 外部に漏れると困る秘密情報
JWTに入れるのは、最低限の識別情報に留めるのが基本。
サーバーは何を検証するか
JWTを受け取ったサーバーは、主に次を確認する。
- 署名が正しいか
- 有効期限が切れていないか
- payloadの中身がアプリの想定どおりか
署名検証には JWT_SECRET のような秘密鍵を使う。
この秘密鍵が漏れると、不正なJWTを作られる危険があるため、コードに直書きせず .env などで管理する。
セッション認証との違い(ざっくり)
従来のセッション認証では、サーバー側にセッション情報を保存し、ブラウザにはセッションIDを持たせることが多い。
JWT認証では、クライアントがJWTを持ち、サーバーはリクエストごとにJWTを検証する。
そのため、サーバー側にセッション保存を持たずに済む構成を作りやすい。
ただし、JWTには注意点もある。
- 盗まれると有効期限まで使われる可能性がある
- 一度発行したトークンを途中で無効化する設計は少し難しい
- 保存場所(localStorage / Cookieなど)にはセキュリティ上の判断が必要
参考:NestJSでの使用例
NestJS Guard / JWT認証では、次の用途でJWTを使う。
POST /auth/login
↓
メールアドレスとパスワードを検証
↓
JWTを発行
↓
GET /users/me に Authorization: Bearer <JWT> を付けてアクセスNestJS側では、JwtStrategy がJWTを検証し、JwtAuthGuard が「このAPIに入ってよいか」を判定する。