# Auth Service

# Auth Service — SRS/SDD Document

| Version | Version Date | Editor | Memo |
|---------|--------------|--------|------|
| 1.0.0 | 2026/05/21 | Gateway Team | 初版：Gateway Auth 模組 SDD |

---

## 1. Introduction

### 1.1 Purpose

Auth 模組為 TianTing Gateway 的**認證領域層**，提供租戶範圍內的原子化認證原語：邀請碼、註冊稽核、OAuth 暫存 Session、CloudEP JWT 簽發／刷新／登出。完整 HTTP 流程由 `internal/logic/auth/` 編排，並與 ZITADEL（身份）、Member（會員）、Notification（通知）協作。

### 1.2 Scope

**範圍內：**

- 租戶邀請碼（Validate / Consume）
- 註冊稽核 metadata（條款版本、渠道、行銷 opt-in）
- OAuth 社交註冊／登入暫存 Session（Redis）
- CloudEP JWT access / refresh token 生命週期
- JWT 黑名單與 jti pair 管理

**範圍外（委派其他模組）：**

- 使用者身份建立 → ZITADEL
- 會員 profile、OTP → Member 模組
- 郵件／簡訊 → Notification 模組
- RBAC 授權 → Permission 模組 + Casbin middleware

### 1.3 Definitions, Acronyms, and Abbreviation

| 縮寫 | 說明 |
|------|------|
| **JWT** | JSON Web Token，CloudEP 自簽 access / refresh token |
| **JTI** | JWT ID，用於黑名單與 pair 映射 |
| **ROPG** | Resource Owner Password Grant，密碼登入 |
| **OIDC** | OpenID Connect，社交登入／SSO |
| **OTP** | One-Time Password，由 Member 模組管理 |
| **Tenant** | 租戶，多租戶隔離單位 |
| **UID** | 租戶內可讀會員識別碼（如 `ACME-10000003`） |

### 1.4 Technologies to be used

| 項目 | 技術 |
|------|------|
| Application Language | Go 1.22+ |
| Framework | go-zero (`rest`, `logx`, `stores/redis`) |
| Cache / Session | Redis |
| Database | MongoDB |
| JWT | `github.com/golang-jwt/jwt/v4`（HS256） |
| Identity Provider | ZITADEL（`internal/library/zitadel`） |
| API Codegen | goctl / `.api` 檔 |

### 1.5 Overview

Auth 模組採 Clean Architecture 分層：`domain/` 定義介面與實體，`repository/` 實作 Mongo / Redis 適配器，`usecase/` 提供原子 UseCase。HTTP handler 不直接存取 repository，而是由 logic 層串接 ZITADEL + Member + Auth 原語。

主要流程：

1. **Email 註冊**：Consume invite → ZITADEL 建 user → Member 建 unverified → 發 OTP → confirm 後 Activate + IssuePair
2. **密碼登入**：ZITADEL ROPG → 查 Member → IssuePair
3. **社交註冊／登入**：Redis Session 暫存 OAuth state → callback 換 token → Provision / Login
4. **Token 刷新／登出**：Refresh 黑名單舊 pair 後重簽；Logout 黑名單 access + refresh jti

---

## 2. System Overview

Auth 模組是 Gateway 認證子系統的核心，負責：

- 控制誰可以註冊（邀請碼）
- 記錄註冊合規稽核
- 管理短期 OAuth 流程狀態
- 簽發與驗證 CloudEP JWT（middleware `AuthJWT`）

對外透過 `/api/v1/auth/*` REST API 暴露；JWT 驗證後將 `(tenant_id, uid)` 注入 request context，供 Member / Permission 等下游使用。

---

## 3. System Architecture

### 3.1 System Architecture

```mermaid
flowchart TB
    subgraph Client["Client / Frontend"]
        Web[Web / Mobile App]
    end

    subgraph Gateway["Gateway"]
        Handler["handler/auth"]
        Logic["logic/auth<br/>(orchestration)"]
        subgraph AuthModule["internal/model/auth"]
            UC["usecase/"]
            Repo["repository/"]
            Domain["domain/"]
        end
        MW["middleware/AuthJWT"]
    end

    subgraph External["External Services"]
        Zitadel[ZITADEL IdP]
        Mongo[(MongoDB)]
        Redis[(Redis)]
    end

    subgraph Sibling["Sibling Modules"]
        Member[member]
        Notif[notification]
    end

    Web --> Handler
    Handler --> Logic
    Logic --> UC
    Logic --> Zitadel
    Logic --> Member
    Logic --> Notif
    UC --> Repo
    Repo --> Mongo
    Repo --> Redis
    MW --> UC
```

### 3.2 Decomposition Description

| 套件 | 職責 |
|------|------|
| `config/` | JWT TTL、Session TTL 設定 |
| `domain/entity/` | Mongo 文件模型（InviteCode、RegistrationMetadata） |
| `domain/enum/` | RegistrationChannel（email / google） |
| `domain/repository/` | Port 介面 + Redis Session struct |
| `domain/usecase/` | UseCase 介面 + DTO |
| `domain/const.go` | BSON 欄位名、Redis key、邀請碼 hash helper |
| `domain/errors.go` | 領域 sentinel errors |
| `repository/` | Mongo + Redis 適配器、`EnsureMongoIndexes` |
| `usecase/` | 實作 + `NewModuleFromParam` factory |
| `usecase/module.go` | 組裝 Invite / RegistrationMeta / Session UseCase |

**ServiceContext 注入：**

| 欄位 | UseCase | 條件 |
|------|---------|------|
| `AuthInvite` | InviteUseCase | Mongo + Redis |
| `AuthRegistrationMeta` | RegistrationMetaUseCase | Mongo |
| `AuthRegistrationSession` | RegistrationSessionUseCase | Redis |
| `AuthLoginSession` | LoginSessionUseCase | Redis |
| `AuthToken` | TokenUseCase | JWT secret + Redis（獨立於 Module） |

### 3.3 Token

CloudEP JWT 採 HS256，access / refresh 使用不同 secret。

**Claims 結構：**

| Claim | 說明 |
|-------|------|
| `tenant_id` | 租戶 ID |
| `uid` | 會員 UID |
| `typ` | `access` 或 `refresh` |
| `auth_gen` | 簽發世代（用於強制登出） |
| `jti` | Token 唯一 ID |
| `iat` / `exp` | 簽發／過期時間 |

**預設 TTL：**

| Token | 預設 |
|-------|------|
| Access | 900 秒（15 分鐘） |
| Refresh | 604800 秒（7 天） |
| Registration Session | 600 秒（10 分鐘） |

**Redis 映射：**

| Key | 用途 |
|-----|------|
| `auth:jwt:pair:{jti}` | access ↔ refresh jti 雙向映射 |
| `auth:jwt:bl:{jti}` | 已登出／已刷新的 jti 黑名單 |

**Refresh 流程：**

```mermaid
sequenceDiagram
    participant C as Client
    participant L as TokenRefreshLogic
    participant T as TokenUseCase
    participant R as Redis

    C->>L: POST /auth/token/refresh {refresh_token}
    L->>T: Refresh(refreshToken)
    T->>T: Parse + verify typ=refresh
    T->>R: Blacklist old refresh jti + paired access jti
    T->>T: IssuePair(new access + refresh)
    T->>R: SavePair(new jti mapping)
    T-->>L: TokenPair
    L-->>C: AuthTokenData
```

### 3.4 Invite Code

邀請碼以 SHA-256 hash 儲存，明文永不落庫。

| 操作 | 行為 |
|------|------|
| **Validate** | 依 `(tenant_id, code_hash)` 查詢，檢查過期與剩餘次數 |
| **Consume** | Redis SETNX lock（30s）→ 原子 `$inc used_count` |

**消費時機：**

- Email 註冊：在 `/register` 起始即 Consume
- 社交註冊：Start 僅 Validate；Callback 才 Consume

### 3.5 OAuth Session

| Session 類型 | Redis Key | State 前綴 | 用途 |
|-------------|-----------|-----------|------|
| Registration | `auth:register:session:{id}` | `reg:` | 社交註冊暫存 invite / terms |
| Login | `auth:login:session:{id}` | `login:` | 社交登入暫存 tenant / redirect |

---

## 4. Data Design

### 4.1 Data Dictionary

#### invite_codes（MongoDB）

| Field | Type | Comment | Index |
|-------|------|---------|-------|
| _id | ObjectId | PK | PK |
| tenant_id | String | 租戶 ID | Unique(tenant_id, code_hash) |
| code_hash | String | SHA-256(normalized code) | Unique(tenant_id, code_hash) |
| max_uses | Int64 | 最大可用次數 | — |
| used_count | Int64 | 已使用次數 | — |
| expires_at | Int64 | 過期時間 ms（0=永不過期） | — |
| new_users_only | Bool | 僅限新用戶（社交註冊） | — |
| create_at | Int64 | 建立時間 ms | — |
| update_at | Int64 | 更新時間 ms | — |

#### registration_metadata（MongoDB）

| Field | Type | Comment | Index |
|-------|------|---------|-------|
| _id | ObjectId | PK | PK |
| tenant_id | String | 租戶 ID | Unique(tenant_id, uid) |
| uid | String | 會員 UID | Unique(tenant_id, uid) |
| invite_code_id | String | 使用的邀請碼 ID | — |
| accept_terms_version | String | 接受的服務條款版本 | — |
| marketing_opt_in | Bool | 行銷 opt-in | — |
| registration_channel | String | email / google | — |
| client_ip | String | 註冊 IP | — |
| user_agent | String | User-Agent | — |
| occurred_at | Int64 | 事件時間 ms | — |
| create_at | Int64 | 建立時間 ms | — |

#### Redis Session / Token Keys

| Key Pattern | Type | TTL | Comment |
|-------------|------|-----|---------|
| auth:register:session:{id} | String(JSON) | 600s | 社交註冊 OAuth session |
| auth:login:session:{id} | String(JSON) | 600s | 社交登入 OAuth session |
| auth:invite:consume:{tenant}:{hash} | String | 30s | 邀請碼消費鎖 |
| auth:jwt:pair:{jti} | String | token TTL | access↔refresh 映射 |
| auth:jwt:bl:{jti} | String | 至自然過期 | JWT 黑名單 |

---

## 5. API Design

**Base Path：** `/api/v1/auth`

### 5.1 Public Endpoints（無 Bearer）

| Method | Path | 說明 |
|--------|------|------|
| POST | `/register` | Email 註冊（回傳 challenge_id） |
| POST | `/register/confirm` | OTP 確認 → 核發 JWT |
| POST | `/register/resend` | 重發註冊 OTP |
| POST | `/register/social/start` | 社交註冊 OAuth 起始 |
| GET | `/register/social/callback` | 社交註冊 OAuth callback |
| POST | `/login` | 密碼登入 |
| POST | `/login/social/start` | 社交登入 OAuth 起始 |
| GET | `/login/social/callback` | 社交登入 OAuth callback |
| POST | `/token/refresh` | 刷新 token pair |
| POST | `/token/exchange` | ZITADEL id_token → CloudEP JWT |

### 5.2 Protected Endpoints（需 Bearer JWT）

| Method | Path | 說明 |
|--------|------|------|
| POST | `/logout` | 登出（黑名單 jti） |

完整請求／回應 schema 見 `generate/api/auth.api`；成功 envelope `code=102000`。

---

## 6. Resource

| 資源 | 路徑 |
|------|------|
| API 定義 | `generate/api/auth.api` |
| Logic 編排 | `internal/logic/auth/` |
| JWT Middleware | `internal/middleware/authjwt_*.go` |
| 模組原始碼 | `internal/model/auth/` |
| 設定範例 | `etc/gateway.dev.example.yaml` → `Auth` / `JWT` 區塊 |
| 設計參考 | `docs/identity-member-design.md` |
