# OAuth Scope 現況 本文只記錄目前程式已註冊與 seed 的 scope。Client Credentials 與 Authorization Code 實際核發的 scope 由 OAuth application `usage` 對應的 DB mapping 決定,不接受呼叫端自行擴權。修改預設 mapping 後,既有環境需執行 `sync-oauth-clients`。 ## 授權邊界 - `profile:*` 是 current-user scope,資料主體固定為 access token 的 `sub`,不能查詢其他會員。 - Email 不是跨會員 lookup key;目前沒有 by-email service API。 - Tenant scope 必須帶有效 `tenant_id`,且與 request/list tenant 相符;缺少或不符時 fail-closed。 - `.global` scope 不依賴 tenant claim,只應授予平台級 confidential client。 - Superuser/Admin 後台權限不使用 OAuth scopes,而使用 Web role + Admin Permission。 ## Resource / Audience | Resource | 預設 audience | Tenant | Scopes | |---|---|---|---| | `member_center_api` | `member_center_api` | scope 個別判定 | OIDC、`profile:*`、`newsletter:list.*`、`newsletter:subscriptions.*`、`newsletter:events.*` | | `send_engine_api` | `send_engine_api` | 必須 | `newsletter:send.read`、`newsletter:send.write` | | `file_access_api` | `file_access_api` | 必須 | `files:*` | Token audience 由 scope → resource registry 計算。 ## Scope Catalog ### OIDC | Scope | 能力 | |---|---| | `openid` | OpenID Connect subject / ID token。 | | `email` | Email claim。 | | `profile` | 標準 OIDC profile scope;實際會員 API 仍需細分的 `profile:*`。 | ### Current-user Profile | Scope | 能力 | |---|---| | `profile:basic.read` | 讀取目前登入會員基本資料。 | | `profile:basic.write` | 修改目前登入會員基本資料。 | | `profile:addresses.read` | 讀取目前會員地址簿。 | | `profile:addresses.write` | 新增、修改、刪除目前會員地址。 | | `profile:subscriptions.read` | 讀取目前會員的電子報訂閱。 | | `profile:subscriptions.write` | 取消目前會員自己的訂閱。 | ### Newsletter / Member Center | Scope | Tenant 規則 | 能力 | |---|---|---| | `newsletter:list.read` | token tenant 必須擁有 list | 依 list 讀取訂閱名單。 | | `newsletter:list.read.global` | 平台級 | 跨 tenant 讀取訂閱名單。 | | `newsletter:subscriptions.read` | token tenant 必須擁有 list | 依 list + email 讀取訂閱偏好。 | | `newsletter:subscriptions.write` | token tenant 必須擁有 list | 建立訂閱、簽發一般退訂 token、更新偏好。 | | `newsletter:events.read` | 依 resource service 規則 | 讀取電子報事件;目前 Member Center 無直接 endpoint。 | | `newsletter:events.write` | `tenant_id` 必須匹配 | Tenant 事件回寫、one-click token、disable subscription。 | | `newsletter:events.write.global` | 平台級 | 跨 tenant 事件回寫、one-click token、disable subscription、webhook client mapping。 | ### Send Engine | Scope | 能力 | |---|---| | `newsletter:send.write` | 在 Send Engine 建立/執行發送工作。 | | `newsletter:send.read` | 在 Send Engine 讀取發送狀態。 | 上述 scope 的資源是 Send Engine,不是 Member Center controller。 ### File Access | Scope | 能力 | |---|---| | `files:upload.write` | File Access service 上傳檔案。 | | `files:download.read` | Access agent 呼叫 Member Center 驗證 delegated download token。 | | `files:download.delegate` | 業務服務向 Member Center 簽發短效 download token。 | | `files:metadata.read` | File Access service 讀取檔案 metadata。 | | `files:delete` | File Access service 刪除檔案。 | `files:upload.write`、`files:metadata.read`、`files:delete` 由 File Access service 驗證;Member Center 目前只提供 delegated token issuing / validation。 ## Client Usage 預設 Mapping | Usage | Client 型態 / Tenant | 預設 scopes | |---|---|---| | `web_login` | public 或 confidential;互動式登入 | `openid`、`email`、`profile`、全部 current-user `profile:*` | | `tenant_api` | confidential;必須綁 tenant | `newsletter:events.write`、`newsletter:list.read`、`newsletter:subscriptions.read/write`、全部 `profile:*` | | `platform_service` | confidential;可不綁 tenant | `newsletter:events.write.global`、`newsletter:list.read.global`、全部 `profile:*` | | `send_api` | confidential;必須綁 tenant | `newsletter:send.read/write` | | `file_api` | confidential;必須綁 tenant | 全部 `files:*` | | `webhook_outbound` | 現有 webhook credential usage | `openid`、`email`、`profile`、`newsletter:events.write` | Mapping seed 採完整集合同步:從預設 mapping 移除的 scope 會在 DB mapping 停用。個別 OAuth application permissions 由 Installer `sync-oauth-clients` 更新。 現有 `tenant_api` / `platform_service` mapping 雖包含 `profile:*`,但 current-user endpoint 仍要求 `sub` 對應實際會員;Client Credentials principal 不能用這些 endpoint 查詢其他會員。目前沒有 S2S 會員資料 endpoint。 ## Member Center Endpoint 對照 | Endpoint | Scope | |---|---| | `GET /user/profile` | `profile:basic.read` | | `POST /user/profile` | `profile:basic.write` | | `GET /user/addresses` | `profile:addresses.read` | | `POST /user/addresses`、`DELETE /user/addresses/{id}` | `profile:addresses.write` | | `GET /user/subscriptions` | `profile:subscriptions.read` | | `POST /user/subscriptions/{id}/unsubscribe` | `profile:subscriptions.write` | | `POST /newsletter/subscribe` | `newsletter:subscriptions.write` | | `POST /newsletter/unsubscribe-token` | `newsletter:subscriptions.write` | | `GET /newsletter/preferences` | `newsletter:subscriptions.read` | | `POST /newsletter/preferences` | `newsletter:subscriptions.write` | | `GET /newsletter/subscriptions` | `newsletter:list.read` 或 `.global` | | `POST /newsletter/one-click-unsubscribe-token(s)` | `newsletter:events.write` 或 `.global` | | `POST /subscriptions/disable` | `newsletter:events.write` 或 `.global` | | `POST /integrations/send-engine/webhook-clients/upsert` | `newsletter:events.write.global` | | `POST /file-access/download-tokens` | `files:download.delegate` | | `POST /file-access/download-tokens/validate` | `files:download.read` | 以下端點依一次性 token 操作,不要求 OAuth scope:`GET /newsletter/confirm`、`POST /newsletter/unsubscribe`。公開 auth endpoint(register、forgot/reset、email verify)亦不屬於 scope 授權模型。