./knowledge-base/docs/okta-auth-architecture.md

# 🔐 Okta 認証アーキテクチャ

> 最終更新: 2026-03-17
> ステータス: **移行完了**(会社 Okta `nhk.okta.com` への移行は 2026年3月4日 に完了)

---

## 概要

時代考証アシストシステムでは、**`/era-assist/` ページへのアクセスに Okta 認証** を使用しています。
番組制作スタッフなど、Okta アカウントを持つ NHK 社員のみが利用できます。

| 項目         | 値                                                               |
| ------------ | ---------------------------------------------------------------- |
| 対象 URL     | `https://historical-research-dev.xmc.nhk.or.jp/era-assist/`     |
| 認証方式     | OIDC / Authorization Code + **PKCE**                             |
| Okta テナント | `nhk.okta.com`                                                   |
| Client ID    | `0oa10n3lsio10F5TG698`                                           |
| Issuer URI   | `https://nhk.okta.com/oauth2/default`                            |

> 💡 **PKCE とは?**
> ブラウザ上で動く Web アプリは、パスワードのような秘密情報(Client Secret)を安全に保管できません。
> そのため、代わりに「使い捨てのランダムコード」で認証を保護する仕組みが PKCE です。Client Secret は不要です。

---

## システム構成

```mermaid
graph LR
    User["👤 ユーザー\n(社内ブラウザ)"]
    CF["☁️ CloudFront\nhistorical-research-dev\n.xmc.nhk.or.jp"]
    Okta["🔑 Okta\nnhk.okta.com"]
    S3["📦 S3\nReact SPA\n(ログイン画面等)"]
    Edge["⚡ Lambda@Edge\nCookie 認証ガード"]
    App["🚀 App Runner\n時代考証アシスト"]

    User -->|"① アクセス"| CF
    CF -->|"静的ファイル配信"| S3
    S3 -->|"② 未認証 → Okta サインイン画面へ"| Okta
    Okta -->|"③ 認証後 → /login/callback へリダイレクト"| S3
    S3 -->|"④ トークンを Cookie に保存"| User
    User -->|"⑤ /era-assist/ にアクセス"| CF
    CF -->|"⑥ Cookie を確認"| Edge
    Edge -->|"認証済み → 通過"| App
    Edge -->|"未認証 → / へリダイレクト"| User
```

**ポイント:**
- ユーザーのブラウザと Okta が直接 OIDC 認証を行います(バックエンドサーバー経由ではありません)
- 認証後に発行されたアクセストークンを Cookie(`okta_access_token`)に保存します
- `/era-assist/` へのアクセス時、Lambda@Edge が Cookie を確認して未認証ならトップページへリダイレクトします

---

## 認証フロー

```mermaid
sequenceDiagram
    actor User as ユーザー
    participant App as Webアプリ(ブラウザ)
    participant Okta as Okta (nhk.okta.com)
    participant Edge as Lambda@Edge

    User->>App: /era-assist/ にアクセス
    App->>Edge: Viewer Request(Cookie を確認)
    Edge-->>App: 未認証のため / へリダイレクト

    User->>App: サインインボタンをクリック
    App->>Okta: Okta サインイン画面へリダイレクト(PKCE フロー開始)
    Note over Okta: ユーザーが社内 ID/PW でログイン

    Okta-->>App: 認証コードを発行して /login/callback へリダイレクト
    App->>Okta: 認証コード → アクセストークンに交換
    Okta-->>App: アクセストークン・IDトークン発行

    Note over App: トークンを Cookie にセット<br/>(okta_access_token)

    User->>App: /era-assist/ に再アクセス
    App->>Edge: Viewer Request(Cookie を確認)
    Edge-->>App: 有効なトークン → App Runner へ通過
    App-->>User: 時代考証アシスト画面を表示
```

---

## Okta アプリ設定

| 項目                  | 値                                                               |
| --------------------- | ---------------------------------------------------------------- |
| アプリタイプ          | Single-Page Application(SPA)                                   |
| 認証フロー            | Authorization Code + PKCE                                        |
| Sign-in Redirect URI  | `https://historical-research-dev.xmc.nhk.or.jp/login/callback`  |
| Sign-out Redirect URI | `https://historical-research-dev.xmc.nhk.or.jp`                  |
| Allowed grant types   | Authorization Code のみ                                          |
| アプリ割り当て        | 全ユーザー(グループ制限なし)                                   |

---

## 要求スコープ

| スコープ  | 用途                |
| --------- | ------------------- |
| `openid`  | OIDC 認証の基本要件 |
| `profile` | ユーザー名の取得    |
| `email`   | メールアドレスの取得|

---

## Lambda@Edge による認証ガード

`/era-assist/*` へのリクエストは、CloudFront の Viewer Request フェーズで **Lambda@Edge** が Cookie を確認します。

```
ユーザーのリクエスト
        ↓
Lambda@Edge(EraAssistEdgeAuth)
        ↓
    Cookie あり・有効期限内?
    ┌── YES ──→ App Runner へ転送(Next.js 画面を表示)
    └── NO  ──→ / へリダイレクト(ログイン画面へ)
```

Lambda@Edge のコードは [knowledge-base/lambda/edge-auth/](../lambda/edge-auth/) にあります。

---

## トラブルシューティング

| 症状 | 確認するポイント |
| ---- | --------------- |
| ログイン後に `/era-assist/` に戻れない | `Sign-in Redirect URI` が Okta に正しく登録されているか確認 |
| ログインページが無限ループする | Cookie の `okta_access_token` が正しくセットされているか確認(ブラウザの開発者ツール) |
| 「アクセスが拒否されました」と表示される | Okta のアプリにユーザーが割り当てられているか確認 |
| 変更が反映されない | CloudFront キャッシュが残っている可能性があります。[Actions タブ](https://github.com/nhk-ds/HistoricalAccuracy/actions) からフロントエンドを再デプロイしてください |