依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類 共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git), 讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等 per-branch 筆記。 - 02-prd/ 21 個檔(PRD、features、market-analysis 等) - 03-design/ 18 個檔(design-spec、wireframes、flows 等) - 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等) - 07-delivery/ 3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup) 合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv, 但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
185 lines
7.9 KiB
Markdown
185 lines
7.9 KiB
Markdown
# Phase 0.6 OIDC 接入 — 交接摘要
|
||
|
||
> 日期:2026-04-26
|
||
>
|
||
> 範圍:visionA-backend StaticAuthProvider → Innovedus Member Center OIDC(BFF Pattern + Authorization Code + PKCE)
|
||
>
|
||
> 上位文件:`.autoflow/04-architecture/oidc-tdd.md`、`.autoflow/04-architecture/adr/adr-010-oidc-bff.md`、`.autoflow/04-architecture/adr/adr-011-supersede-static-auth.md`
|
||
>
|
||
> 整體交付:見 `.autoflow/07-delivery/project-summary.md`
|
||
|
||
---
|
||
|
||
## 1. Phase 0.6 完成項目
|
||
|
||
### Backend(OB1-OB6)✅
|
||
- **OB1** `internal/oidc/`:coreos/go-oidc 包裝,discovery + JWKS + token exchange + id_token 驗簽(24 tests / 93.4% 覆蓋)
|
||
- **OB2** `internal/usersession/`:in-memory session store + cookie HMAC 簽章(24 tests)
|
||
- **OB3+OB4** `internal/api/middleware/auth.go` + 4 個 OIDC handler(`/api/auth/login` / `/callback` / `/logout` / `/me`)(14 tests)
|
||
- **OB5** 完全移除 `StaticAuthProvider`、AuthenticatedClient fixture 統一(17 packages 全綠 / oidc_e2e build tag 移除)
|
||
- **OB6** ADR-011 推翻 ADR-005 Auth 部分(DB 部分仍有效)
|
||
|
||
### Frontend(OF1-OF2)✅
|
||
- **OF1** login 頁改 OIDC redirect 按鈕(11 tests + i18n)
|
||
- **OF2** API client `credentials: 'include'`、auth-store 拔 localStorage、改 cookie session(107 tests 綠)
|
||
|
||
### Frontend(OF3-OF4)⏳
|
||
- **OF3** register 頁移除、account 接 `/api/auth/me`(待補)
|
||
- **OF4** i18n 補齊(待補)
|
||
|
||
### DevOps(OD1)✅
|
||
- 5 service docker-compose(postgres / member-center / member-center-web / member-center-init / visiona-api / visiona-proxy)全 healthy
|
||
- `docs/DEV-SETUP.md` 完整 setup + 故障排除(含 §7.6 OIDC flow 階段問題)
|
||
|
||
### DevOps(OD2)⏳
|
||
- `make dev-with-mc` Makefile target + `.env.example` 整理(待補;MC bug 修復後加 seed script)
|
||
|
||
### Testing(OT1)✅
|
||
- `internal/oidc/oidctest/`:fake OIDC server(自簽 JWKS / 模擬 authorize / token endpoints)
|
||
- `internal/api/handlers/oidc_e2e_test.go`:6 個 e2e cases(含 `PairingTokenBindsToOIDCUser`,驗 OIDC sub 真的有貫通到 PairingStore)
|
||
- 17 packages 全綠 / build tag 已拿掉(合進主測試)
|
||
|
||
### Testing(OT2)✅(範圍調整)
|
||
- 因 MC 兩個 bug 阻擋自動 e2e(password grant 缺 sub claim、admin API 不接受 client_secret),原訂「真 MC e2e」改為:
|
||
- `docs/SMOKE-TEST.md`:完整 7 階段手動煙測 checklist
|
||
- `docs/DEV-SETUP.md` §7.6 補 OIDC flow 故障排除對照表
|
||
- 真 MC 自動 e2e 列入 Phase 1 TODO(待 MC 修 bug)
|
||
|
||
---
|
||
|
||
## 2. 跑通的 Demo
|
||
|
||
### Demo A:OIDC Flow(手動,需先依 `docs/DEV-SETUP.md` §5 註冊 OAuth client)
|
||
|
||
**端到端使用者旅程**(對應 `docs/SMOKE-TEST.md` 階段 3-7):
|
||
|
||
```
|
||
[browser] http://localhost:3000/login
|
||
↓ 點「使用您的 Innovedus 帳號登入」
|
||
[backend] GET /api/auth/login
|
||
↓ 產 PKCE + state + nonce,存 pending session(10 分鐘 TTL)
|
||
↓ Set-Cookie: visiona_pending_sid
|
||
↓ 302 to MC /oauth/authorize?response_type=code&...&code_challenge=...
|
||
[MC] http://localhost:5050/oauth/authorize
|
||
↓ 顯示登入頁 → demo@visiona.local / Demo12345!
|
||
↓ 同意授權
|
||
↓ 302 back to http://localhost:3721/api/auth/callback?code=...&state=...
|
||
[backend] GET /api/auth/callback
|
||
↓ 驗 state(CSRF)
|
||
↓ POST MC /oauth/token (code + verifier + client_secret)
|
||
↓ 驗 id_token(iss / aud / exp / nonce / JWKS 簽章)
|
||
↓ 建 visionA session(user_id = OIDC sub, 7d / 24h idle)
|
||
↓ Set-Cookie: visiona_session
|
||
↓ 302 to http://localhost:3000{return_to}
|
||
[browser] dashboard 顯示已登入 demo user
|
||
↓ 後續 API request 自動帶 visiona_session cookie
|
||
[backend] /api/devices /api/models /api/auth/me 全帶 cookie 認證
|
||
```
|
||
|
||
### Demo B:Pairing Token 綁 OIDC user(關鍵承諾驗證)
|
||
|
||
**目的**:驗證取代 StaticAuth 後,pairing token 不再綁 `demo-user` 而是真實 OIDC sub。
|
||
|
||
```
|
||
[browser] /devices/pair → 點「產生 Pairing Token」
|
||
[backend] POST /api/pairing/token (cookie: visiona_session)
|
||
↓ middleware 解 cookie → UserContext{UserID: <OIDC sub>}
|
||
↓ PairingStore.Create(userID=<OIDC sub>, token=vAc_xxx)
|
||
↓ log: "PairingStore Create userID=<UUID>"
|
||
[browser] 拿到 token vAc_xxx
|
||
↓ 餵給 local-tool agent
|
||
[agent] 連 visiona-proxy → 帶 pairing token → 換 session token
|
||
[backend] agent 連入 → 後端 binding user_id 是 OIDC sub(與 step 2 一致)
|
||
```
|
||
|
||
### Demo C:fake OIDC e2e(自動化)
|
||
|
||
```
|
||
go test ./internal/api/handlers/... -run TestOIDCE2E
|
||
```
|
||
|
||
跑完含 6 個 case:
|
||
- LoginRedirectsToProvider
|
||
- CallbackCreatesSession
|
||
- StateMismatchRejected
|
||
- NonceMismatchRejected
|
||
- ExpiredTokenRejected
|
||
- **PairingTokenBindsToOIDCUser**(最關鍵)
|
||
|
||
17 packages 全綠 / build tag 已合進主測試。
|
||
|
||
---
|
||
|
||
## 3. 手動 Demo Flow
|
||
|
||
完整步驟見 **`docs/SMOKE-TEST.md`**,7 階段 / 預估 30 分鐘:
|
||
|
||
| 階段 | 內容 | 時間 |
|
||
|------|------|------|
|
||
| 1 | 基礎服務驗證(5 service + frontend healthy)| 5 min |
|
||
| 2 | MC 設定(建 tenant + OAuth client + demo user)| 10 min |
|
||
| 3 | 完整 Login Flow(redirect chain 走完)| 5 min |
|
||
| 4 | API 帶 Cookie 驗證(/me + /devices + /models)| 3 min |
|
||
| 5 | Pairing Token 綁 OIDC user(**關鍵承諾**)| 5 min |
|
||
| 6 | 登出 + 重登 | 3 min |
|
||
| 7 | 跨頁 Refresh / 持久化 | 2 min |
|
||
|
||
每個階段都有對應的「故障排除 #N」可查;卡住先看 `docs/SMOKE-TEST.md` §故障排除 + `docs/DEV-SETUP.md` §7。
|
||
|
||
---
|
||
|
||
## 4. 已知 Limitation
|
||
|
||
| # | Limitation | 影響範圍 |
|
||
|---|-----------|---------|
|
||
| 1 | MC admin API 不能 seed OAuth client(password grant + client_secret 兩個 bug)| §2 OAuth client 註冊必須手動走 Web UI;自動 e2e blocked |
|
||
| 2 | MC 只支援 `usage=webhook_outbound` 帶 redirect_uris | 雛形借用,命名語意不對 |
|
||
| 3 | visionA-backend in-memory session store 重啟即消失 | 所有 user 重登 |
|
||
| 4 | 沒有 RP-initiated logout | 登出 visionA 不會把 MC session 也登出 |
|
||
| 5 | 沒有 refresh token rotation | 24h idle / 7d absolute 後必須重登 |
|
||
| 6 | host visiona-local(local-tool)佔 3721 與 docker compose 衝突 | 兩個只能擇一跑 |
|
||
|
||
---
|
||
|
||
## 5. Phase 1 TODO
|
||
|
||
### MC team(unblock visionA 自動化)
|
||
- [ ] **MC-1** 修 password grant Identity user 缺 sub claim → 500 bug
|
||
- [ ] **MC-2** admin API 接受 + 回傳 client_secret
|
||
- [ ] **MC-3** 新增 `usage=web_app` OAuth client 類型
|
||
|
||
### visionA Phase 1
|
||
- [ ] **OD2** `make dev-with-mc` + `make dev-seed` script(依賴 MC-1 + MC-2)
|
||
- [ ] **OT2 補完** 真 MC 自動 e2e(用 testcontainers 起真 MC,把 SMOKE-TEST §3-§7 全自動)
|
||
- [ ] **OF3 OF4** register 頁移除 + account 改造 + i18n 補齊
|
||
- [ ] **OB-Phase1-1** in-memory session store → Redis
|
||
- [ ] **OB-Phase1-2** RP-initiated logout(OIDC end_session_endpoint)
|
||
- [ ] **OB-Phase1-3** Refresh token rotation(依賴 MC 上 refresh token 支援)
|
||
- [ ] **OB-Phase1-4** Member Center webhook(user 刪除 / 停用通知)
|
||
|
||
---
|
||
|
||
## 6. 相關文件索引
|
||
|
||
| 主題 | 文件 |
|
||
|------|------|
|
||
| 架構決策 | `.autoflow/04-architecture/adr/adr-010-oidc-bff.md`、`adr/adr-011-supersede-static-auth.md` |
|
||
| TDD(含時序圖、模組設計、env、安全考量)| `.autoflow/04-architecture/oidc-tdd.md` |
|
||
| Dev 環境 setup | `docs/DEV-SETUP.md` |
|
||
| 手動煙測 | `docs/SMOKE-TEST.md` |
|
||
| 整體 visionA 交付 | `.autoflow/07-delivery/project-summary.md` |
|
||
|
||
---
|
||
|
||
## 7. 驗收狀態
|
||
|
||
- [x] 端到端 redirect chain 通(fake OIDC e2e 自動驗)
|
||
- [x] Pairing token 綁 OIDC sub(OT1 PairingTokenBindsToOIDCUser ✅)
|
||
- [x] StaticAuthProvider 完全移除(OB5 ✅)
|
||
- [x] Frontend 完全不接觸 token(OF1 + OF2 ✅)
|
||
- [x] docker-compose 一鍵起 5 service(OD1 ✅)
|
||
- [x] 手動煙測 checklist 完整(OT2 ✅,本文件對應)
|
||
- [ ] OF3 + OF4 完成(待補;不阻擋 Phase 0.6 驗收,列入 Phase 1)
|
||
- [ ] OD2 Makefile + seed script(依賴 MC bug 修復;列入 Phase 1)
|
||
- [ ] 真 MC 自動 e2e(依賴 MC bug 修復;列入 Phase 1)
|