Files
wmailhub/docs/02_CLOUDFLARE_OAUTH.md
T
bigcode 1f4d45f719 fix: v2.3.1 Cloudflare OAuth scope 点号格式 + 授权失败可读提示 + 配置自检
- 根因:Cloudflare OAuth 的 scope 是点号分隔(account.read),冒号写法不被接受,
  授权端点直接返回 error=invalid_scope。默认 scope 改为
  account.read zone.read email_routing.write workers_scripts.write
- scope 可在设置页自定义(settings.cf_oauth_scopes),需与 App 登记值逐字一致
- 新增 GET /api/oauth/cloudflare/preflight + 设置页「检测授权配置」按钮:
  只读探测授权端点(不跟随跳转),区分 登录同意页 / 弹回回调 / Cloudflare /oauth/error,
  并把 invalid_scope、invalid_request 翻译成可执行的处置建议
- 回调端点处理 error 参数:不再拿空 code 去兑换 token,改为跳回账号页并弹窗说明原因
  (此前会落到 SPA 404 空壳页)
- 账号页读取 ?oauth_error= 弹窗展示 Cloudflare 的原始描述
- docs/02 补 Cloudflare OAuth App 配置清单(Redirect URL / Client URI 域名校验 /
  Promote to public / 点号 scope);83 个测试全通过
2026-09-30 16:08:27 +08:00

4.1 KiB

Cloudflare OAuth 与自动接入(docs/11 §14)

旧「Add Node」概念已删除,改为 Connect Cloudflare Account。

流程

Console
   |
   v
Cloudflare OAuth
   |
   v
用户授权 Account
   |
   v
Console
   +-- 保存 Account
   +-- Account / Zone 发现
   +-- 配置 Domain(同步账号下全部域名,pending)
   +-- 创建 catch-all Mailbox
   +-- 部署账号级 Email Worker
   +-- 签发 WorkerCredential(secret 注入 Worker 脚本)

用户不需要执行安装命令,也不手工创建 API Token。

安全

  • Cloudflare credential(OAuth access token)AES-GCM 加密存储,不进入前端和日志。
  • OAuth state 一次性(用后即删)、5 分钟过期、绑定账号(CSRF 防护)。
  • 授权回调不校验会话:浏览器从 dash.cloudflare.com 跳回 Console 属于跨站顶级导航,SameSite=Strict 的会话 cookie 不会携带;该端点由一次性 state 承担 CSRF 防护,其余 /api/oauth/* 仍要求登录。
  • Account ownership 以 token 实际可访问的 accounts 为准。
  • 安装过程幂等,重复执行不产生重复资源。
  • Worker credential 与 Cloudflare credential 分离;轮换 credential 后已配置域名自动重新部署。

前置条件:OAuth 客户端凭据

授权所需的 Client ID / Secret 有两个来源,settings 表优先、env 兜底:

来源 配置位置 说明
settings(优先) Console「设置 → Cloudflare 接入」 Secret 以 AES-GCM 密文存 settings.cf_oauth_client_secret_enc,只回显末 4 位;保存后立即生效,无需重新部署。清除走 DELETE /api/settings/cf-oauth
env(兜底) CF_OAUTH_CLIENT_ID / CF_OAUTH_CLIENT_SECRET 部署时注入;settings 未配置或密文损坏时使用

两个来源都没有时,/api/oauth/cloudflare/start 与 /api/oauth/cloudflare/callback 一律返回 503 —— 系统不提供任何模拟/降级通道,不会出现"看起来接入成功"的假账号与假资源。 GET /api/settings 会返回 cf_oauth.source(settings / env / none)与 redirect_uri(需在 Cloudflare Dashboard 登记的回调地址),GET /api/oauth/mode 返回 source 供账号页判断。

Cloudflare OAuth App 配置清单(docs 依据:Cloudflare "Create OAuth Client" API)

在 https://dash.cloudflare.com/profile/oauth-apps 新建应用后,必须完成下面几项,否则授权端点 会直接拒绝(此时 Console 收不到 code,只有 error=invalid_scope / invalid_request):

字段 填什么 不对时的报错
Redirect URL(s) https://wmailhub.adx9.com/api/oauth/cloudflare/callback(本地联调另加 http://127.0.0.1:18787/api/oauth/cloudflare/callback) invalid_request: redirect_uri does not match
Client URI Console 站点首页,如 https://wmailhub.adx9.com promotion to public requires a verified client_uri host
域名校验 按 Cloudflare 提示在 client_uri 域下加 TXT 记录(形如 cloudflare_oauth_client_publisher=...) 同上,一直卡在 not verified
Promote to public 应用可见性从 private 提升为 public 私有 App 不可被他人授权
Scopes 与 Console「设置 → Cloudflare 接入」里的 scope 字段逐字一致 invalid_scope: Client is not allowed to request scope '...'

scope 必须是点号分隔

Cloudflare OAuth 的 scope 命名是 account.read 这种点号形式;冒号形式(account:read)不被接受, 授权端点会判为 invalid_scope。默认请求的四个:

account.read  zone.read  email_routing.write  workers_scripts.write

Console 允许在设置里改这个字段,以便与 App 中登记的值保持一致(settings.cf_oauth_scopes)。

授权配置自检(不用开浏览器)

GET /api/oauth/cloudflare/preflight 用当前配置请求一次 Cloudflare 授权端点但不跟随跳转,据跳转目标判定:

  • 跳到登录/同意页 → ok: true,配置可用;
  • 弹回我们的回调地址,或跳 dash.cloudflare.com/oauth/error → ok: false 并带回 error / error_description 与一条处置建议。

设置页「Cloudflare 接入」tab 的「检测授权配置」按钮就是调它。纯只读探测,不会产生任何授权。