JWT認証とは何か?ログインとの違いを理解する
混乱したきっかけ
@Post('login') // 認証不要(ログイン用)
login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto);
}
@UseGuards(JwtAuthGuard) // ← このメソッドは認証必要
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
「ログインは認証不要なのに、プロフィール取得は認証必要?」
Nest.js触りたてで、この疑問がでてきたので、Claude Sonnet4さんにJWT認証の本質と仕組みを聞きました。
(※ そのまま回答を載せています)
JWT認証が解決する問題
従来の課題:「誰がリクエストしているか分からない」
GET /api/profile
# このリクエストは誰から?本当に信頼できる?
Webは基本的にステートレスなので、サーバーはリクエストを送った人が誰なのか分かりません。
JWT認証の解決策:「身分証明書」の仕組み
GET /api/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# ↑ これが「デジタル身分証明書」
ログインとJWT認証の関係
2段階のプロセス
1段階目:ログイン(身分証明書の発行)
@Post('login') // 認証不要
login(@Body() loginDto: LoginDto) {
// 1. ユーザー名・パスワードをチェック
// 2. 正しければJWTトークン(身分証明書)を発行
return { accessToken: 'jwt-token-here' };
}
なぜ認証不要?
- まだJWTトークンを持っていないから
- ユーザー名・パスワードで本人確認する
- 成功したらJWTトークンを渡す
2段階目:JWT認証(身分証明書の確認)
@UseGuards(JwtAuthGuard) // 認証必要
@Get('profile')
getProfile(@Request() req) {
// JWTトークンで「この人は〇〇さんです」と確認済み
return req.user;
}
なぜ認証必要?
- 個人情報を扱うから
- JWTトークン(身分証明書)で本人確認する
- 偽造されていないかチェックする
具体的な流れ
実際のやり取り
1. 初回ログイン
Client → Server: POST /auth/login { email, password }
Server → Client: { accessToken: "jwt-token" }
2. 以降のAPIアクセス
Client → Server: GET /api/profile (Authorization: Bearer jwt-token)
Server → Client: { user: { name: "田中", email: "tanaka@example.com" } }
身分証明書の例で理解
1. パスポート申請(ログイン)
あなた → 役所: 「戸籍謄本と住民票を提出」
役所 → あなた: 「パスポートを発行」
2. 海外旅行(JWT認証)
あなた → 空港: 「パスポートを提示」
空港 → あなた: 「確認OK、通過してください」
なぜこの仕組みが必要?
問題1:毎回パスワードを送るのは危険
// ❌ 毎回パスワードを送信(危険)
@Get('profile')
getProfile(@Body() loginDto: LoginDto) {
// 毎回ユーザー名・パスワードをチェック
}
問題2:サーバーがセッションを覚えるのは大変
// ❌ サーバーがセッション管理(大変)
// 「user123がログイン中」を覚え続ける
// マイクロサービスでは不可能
JWT認証の解決策
// ✅ 安全で効率的
// 1. 最初だけパスワードチェック
// 2. 以降はJWTトークンで確認
// 3. サーバーはセッション情報を保持不要
JWTトークンの中身
実際のJWTトークン
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLWlkIiwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwiaWF0IjoxNjM5NTIzNDAwfQ.signature
デコードすると
{
"sub": "user-id",
"email": "test@example.com",
"iat": 1639523400,
"exp": 1639609800
}
重要: トークン自体に「誰の」「いつまで有効」が含まれている
認証が必要なAPI vs 不要なAPI
認証不要(誰でもアクセス可能)
@Post('login') // ログイン処理
@Post('register') // 新規登録
@Get('public') // 公開情報
@Get('health') // ヘルスチェック
認証必要(本人確認が必要)
@Get('profile') // 個人情報
@Put('profile') // 個人情報更新
@Get('my-orders') // 注文履歴
@Post('logout') // ログアウト
@Delete('account') // アカウント削除
JWT認証の流れ(完全版)
初回ログイン
1. ユーザー:「メール・パスワードでログインしたい」
2. サーバー:「確認します」→ データベースチェック
3. サーバー:「OK!JWTトークンをどうぞ」
4. ユーザー:JWTトークンを保存
以降のAPIアクセス
1. ユーザー:「プロフィール見たい」+ JWTトークン
2. サーバー:「トークンを確認...OK、田中さんですね」
3. サーバー:「田中さんのプロフィールをどうぞ」
ログアウト後
1. ユーザー:JWTトークンを削除
2. 以降のAPIアクセスは「認証なし」扱い
まとめ
JWT認証とは:
- ログイン後の身分証明システム
- 毎回パスワードを送らずに済む仕組み
- 「この人は確実に〇〇さんです」を証明
ログインとの違い:
- ログイン: 身分証明書をもらう手続き
- JWT認証: 身分証明書を見せて本人確認
なぜ必要?
- セキュリティ(パスワードを毎回送らない)
- 効率性(サーバーがセッション管理不要)
- スケーラビリティ(マイクロサービス対応)
つまり:ログイン = 身分証明書発行、JWT認証 = 身分証明書確認