JWTトークン方式と外部ストア方式（ローカルストレージ）を用いたログインステータス管理方法

# JWT（JSON Web Token）完全理解ガイド

## 1. JWTの基本構造

JWTは3つの部分から構成される文字列です：

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```

**構造**: `ヘッダー.ペイロード.署名`

### 各部分の役割

| 部分 | 内容 | エンコード方式 | 可逆性 |
|------|------|----------------|--------|
| **ヘッダー** | アルゴリズム情報 | Base64URL | 可逆（デコード可能） |
| **ペイロード** | ユーザー情報、有効期限等 | Base64URL | 可逆（デコード可能） |
| **署名** | 改ざん検証用のハッシュ値 | 署名アルゴリズム依存 | 不可逆 |

### 具体例

```typescript
// ヘッダー（JSON → Base64URL）
const header = {
  "alg": "HS256",  // アルゴリズム
  "typ": "JWT"     // トークンタイプ
};

// ペイロード（JSON → Base64URL）
const payload = {
  "user_id": 123,
  "name": "John Doe",
  "exp": 1672531200  // 有効期限
};

// 署名（ハッシュ値）
const signature = HMAC_SHA256(base64Url(header) + "." + base64Url(payload), secretKey);
```

## 2. 全体的なフロー

### ログイン〜API利用までの流れ

```mermaid
sequenceDiagram
    participant C as クライアント
    participant S as サーバー
    
    Note over C,S: 1. ログインフェーズ
    C->>S: ログイン情報（ID/パスワード）
    S->>S: 認証情報を検証
    S->>S: JWTトークンを生成
    S->>C: JWTトークンを返却
    
    Note over C,S: 2. トークン保存フェーズ
    C->>C: JWTをlocalStorage等に保存
    
    Note over C,S: 3. API利用フェーズ
    C->>S: APIリクエスト + JWT
    S->>S: JWTの署名を検証
    alt 検証成功
        S->>C: APIレスポンス
    else 検証失敗
        S->>C: 認証エラー
    end
```

### クライアント側の処理

```typescript
// 1. ログイン
const login = async (credentials) => {
  const response = await fetch('/api/login', {
    method: 'POST',
    body: JSON.stringify(credentials)
  });
  const { token } = await response.json();
  
  // 2. JWTをそのまま保存（一切変更しない）
  localStorage.setItem('jwt', token);
};

// 3. API呼び出し時
const callAPI = async () => {
  const token = localStorage.getItem('jwt');
  const response = await fetch('/api/protected', {
    headers: {
      'Authorization': `Bearer ${token}`  // そのまま送信
    }
  });
};
```

## 3. デジタル署名の仕組み

### 3.1 HMAC方式（対称鍵）

JWTで最も一般的な方式です。

```mermaid
graph TB
    subgraph "署名生成（サーバー側）"
        A[ヘッダー + ペイロード] --> B[HMAC_SHA256]
        C[共有秘密鍵] --> B
        B --> D[デジタル署名]
    end
    
    subgraph "署名検証（サーバー側）"
        E[受信したヘッダー + ペイロード] --> F[HMAC_SHA256]
        G[同じ共有秘密鍵] --> F
        F --> H[期待される署名]
        I[受信した署名] --> J{比較}
        H --> J
        J -->|一致| K[改ざんなし]
        J -->|不一致| L[改ざんあり]
    end
```

#### 特徴
- **軽量**: 処理が高速
- **シンプル**: 鍵管理が簡単
- **制限**: 全サービスが同じ秘密鍵を共有する必要

### 3.2 RSA方式（非対称鍵）

マイクロサービス環境に適した方式です。

```mermaid
graph TB
    subgraph "署名生成（認証サーバー）"
        A[ヘッダー + ペイロード] --> B[SHA256でハッシュ化]
        B --> C[RSA_sign]
        D[秘密鍵] --> C
        C --> E[デジタル署名]
    end
    
    subgraph "署名検証（各サービス）"
        F[受信した署名] --> G[RSA_verify]
        H[公開鍵] --> G
        G --> I[復号されたハッシュ値]
        
        J[受信したヘッダー + ペイロード] --> K[SHA256でハッシュ化]
        K --> L[計算されたハッシュ値]
        
        I --> M{比較}
        L --> M
        M -->|一致| N[改ざんなし]
        M -->|不一致| O[改ざんあり]
    end
```

#### マイクロサービス環境での利点

```mermaid
graph TB
    subgraph "認証サーバー"
        AS[認証サーバー]
        PK[秘密鍵]
        AS --> PK
    end
    
    subgraph "各マイクロサービス"
        US[ユーザーサービス]
        PS[商品サービス]
        OS[注文サービス]
        PUB1[公開鍵]
        PUB2[公開鍵]
        PUB3[公開鍵]
        US --> PUB1
        PS --> PUB2
        OS --> PUB3
    end
    
    AS -->|JWT発行| US
    AS -->|JWT発行| PS
    AS -->|JWT発行| OS
    
    style AS fill:#ff9999
    style PK fill:#ff9999
    style PUB1,PUB2,PUB3 fill:#99ff99
```

**利点**:
- **権限分離**: 認証サーバーのみがJWT発行可能
- **セキュリティ**: 公開鍵漏洩でもJWT作成不可
- **スケーラビリティ**: 新サービス追加時は公開鍵配布のみ

## 4. 改ざん検出の仕組み

### 攻撃者が改ざんを試みた場合

```mermaid
sequenceDiagram
    participant A as 攻撃者
    participant S as サーバー
    
    Note over A,S: 攻撃者の行動
    A->>A: ペイロードを改ざん<br/>{"role":"user"} → {"role":"admin"}
    A->>A: 秘密鍵がないので<br/>正しい署名を作成できない
    A->>A: 元の署名をそのまま使用
    
    Note over A,S: サーバーでの検証
    A->>S: 改ざんJWT + 元の署名
    S->>S: 署名から元データのハッシュ値を取得
    S->>S: 改ざんデータから新しいハッシュ値を計算
    S->>S: 2つのハッシュ値を比較
    Note over S: ハッシュ値不一致 → 改ざん検出
    S->>A: 認証エラー
```

### ハッシュ関数の雪崩効果

```typescript
// わずかな変更でも大きくハッシュ値が変化
const original = '{"user_id":123,"role":"user"}';
const modified = '{"user_id":123,"role":"admin"}'; // 1文字違い

const hash1 = SHA256(original);  // "a1b2c3d4e5f6..."
const hash2 = SHA256(modified);  // "x9y8z7w6v5u4..." (完全に異なる)
```

## 5. セキュリティ考慮事項

### 重要なポイント

1. **トークンの有効期限**: 適切な期限設定でリスク軽減
2. **リフレッシュトークン**: 長期間の認証維持
3. **XSS対策**: CSP設定とhttpOnly Cookieの検討
4. **鍵管理**: 秘密鍵の厳重な管理

### Vue.js + TypeScriptでの実装例

```typescript
// composables/useAuth.ts
export const useAuth = () => {
  const isAuthenticated = ref(false);
  const user = ref<User | null>(null);

  const login = async (credentials: LoginCredentials) => {
    const response = await authAPI.login(credentials);
    const token = response.data.token;
    
    // JWTをそのまま保存
    localStorage.setItem('jwt-token', token);
    isAuthenticated.value = true;
    user.value = response.data.user;
  };

  const checkAuthStatus = () => {
    const token = localStorage.getItem('jwt-token');
    if (token && !isTokenExpired(token)) {
      isAuthenticated.value = true;
    }
  };

  return {
    isAuthenticated: readonly(isAuthenticated),
    user: readonly(user),
    login,
    checkAuthStatus
  };
};
```

## 6. まとめ

### JWTの核心メカニズム

1. **ステートレス認証**: サーバー側でセッション保持不要
2. **改ざん検出**: デジタル署名によるデータ整合性保証
3. **権限分離**: 認証サーバーと各サービスの責務分離
4. **スケーラビリティ**: マイクロサービス環境に最適

### 理解のポイント

- **クライアント側**: JWTを一切変更せず、そのまま保存・送信
- **サーバー側**: 署名検証により改ざんの有無を確実に検出
- **セキュリティ**: ハッシュ値の比較により、わずかな改ざんも検出可能
- **実装**: フロントエンドでの状態管理と適切なAPI呼び出し

JWTは「データの改ざん = ハッシュ値の変化 = 署名との不一致 = 改ざん検出」という連鎖により、堅牢なセキュリティを実現しています。