架構決策 (ADR)
採 Firebase Auth 當 identity broker,後端 token exchange 保留自有 JWT 與 device HMAC
Context
YiBi 自建認證(Google SSO + email/password + 自簽 JWT;device 走 HMAC→15min JWT,ADR-0010 offline-first)。 四個壓力推動改變:(1) App Store Guideline 4.8 強制 Apple Sign-In;(2) email 基礎設施 (驗證信/magic link/重設/rate limit/bot 防護)自建成本高;(3) 降低自建認證安全/維運負擔; (4) 對齊競品(YoTo→Auth0、Tonies→Keycloak)架構意圖。
限制條件:
- 已 GCP-native(Cloud SQL Postgres、Vertex AI、Cloud Run)。
- 3 人技術團隊 — self-host 維運負擔依 ADR-0010 §5.2 先例視為 net-negative。
- 已有真實 user(
users.google_id= Google sub、bcrypt 密碼、family/family_member FK)。 - device HMAC auth 是刻意的 offline-first 設計,無任何託管 IdP 原生支援。
- 兒童 domain data(family/child/persona/consent/deletion)是自有 PostgreSQL 表,IdP 不託管。
Decision
結論:採 Firebase Auth 當 identity broker + 後端 token exchange;後端維持 identity→family 對應與 JWT 簽發的 source of truth,device HMAC 與 domain 邏輯不變。
流程:
- Mobile 用 Firebase Auth SDK 完成 Apple/Google/email-magic-link 登入,取得 Firebase ID token(1h)。
- Mobile 以 Firebase ID token 呼叫新端點
POST /api/v1/auth/firebase。 - 後端用 firebase-admin(或 Google public keys + 驗
aud=project id、iss=securetoken)驗 token, 取 canonical identity:firebase_uid+ provider + 底層 provider sub。 - 後端跑既有帳號連結邏輯,簽發自有的 access/refresh JWT(現有 rotation 不變)。
- 下游
auth_interceptor.dart、token_store.py、device HMAC 完全不動。
設計決策:
- identity anchor 改
firebase_uid;Firebase ID token 僅用於該次交換,不作 session。 - 同時持久化底層 provider sub(google sub / apple sub),保留離開 Firebase 後重新連結的能力 (降低 Firebase 帳號連結語義的軟綁定)。
- 既有 user lazy migration:首次 Firebase 登入用 email 比對既有 row → 回填
firebase_uid(不建新帳號);bcrypt 密碼留後端,不匯入 Firebase。 - Apple private relay:Apple email 只第一次給且為
@privaterelay.appleid.com,故連結 key 在firebase_uid/provider sub,不可 key 在 email。 - 一律補齊 consent(
consented_at/policy_version/consent_ip_address),不分 provider。
Alternatives Considered
- 方案 A:維持純自建,只原生加 Apple Sign-In — 鏡像現有 Google flow,零遷移、零新相依。 否決主因:解不掉 email 基礎設施 + bot 防護兩個明確痛點,等於只做一半還要再做一次。
- 方案 B(本案):Firebase broker + 後端 token exchange — 最低改動同時命中四個動機; 保留既有成熟資產(refresh rotation、帳號連結、device offline-first、COPPA deletion spec); GCP-native 摩擦最低。
- 方案 C:Supabase Auth — 功能等價,但屬另一套 infra,且若連 domain data 也託管即「換資料庫」, 遠超換認證範疇。否決:相對 Firebase 無 GCP-native 優勢,增加 infra 面。
- 方案 D:Auth0 — 功能完整但規模化後成本高;對 3 人團隊 CP 值低於 Firebase。否決。
- 方案 E:Keycloak(self-host) — 違反 ADR-0010 §5.2 self-host net-negative 先例 (Tonies 有平台團隊養它,本團隊無)。否決。
關鍵反駁:使用者原始論述把「硬體裝置配對」「兒童連帶刪除」列為「需要 IdP」的理由, 但 device HMAC 任何 IdP 都不支援(照樣自留),兒童 domain data 連帶刪除是自有表 (不管用不用 IdP 都得自寫)。IdP 真正的淨收益只在 email 基礎設施 + bot 防護 + 託管登入 UI。
Consequences
好:
- 一次解決 Apple 上架 + email 基礎設施 + bot 防護(App Check);自建安全面縮小。
- 後端持 token 簽發 = session 層換 IdP 仍有彈性;存 provider sub = identity 連結層保留可攜性。
- 既有 refresh rotation / device HMAC / domain 邏輯零改動。
壞 / 代償:
- 後端新增 firebase-admin 相依 + Firebase project 設定。
- 既有 user 須 lazy 回填
firebase_uid(雖低風險,仍是 identity anchor 切換)。 - Firebase 帳號連結語義有軟綁定(靠存 provider sub 緩解,非全免)。
- 兒童相關 PII 經 Google Firebase 處理 → E26 regional compliance matrix / DPA 須補記載。
中性:
users表新增firebase_uid+ provider sub 欄位,migration 須與 0020token_version協調。- 需補整合測試:persona 解析(0023)在 Apple/Firebase 登入下正確。