ADR-0013:公开 API / MCP
- 状态:✅ 已接受(人工解封 2026-08-04;切片 1–5 ✅ +
projects:writeREST/MCP ✅ + Redis 限流 ✅ + OAuth 切片 A+B ✅ + client / PAT 管理 UI ✅ + 同意页 ✅ + refresh_token ✅ + OIDC 薄 MVP ✅ + nonce/at_hash ✅ + RS256·JWKS ✅) - 决策者:项目维护者(Vision 自动轨暂停点
785d699后显式选择本 ADR 为下一里程碑) - 前置:ADR-0012 选项 B 已接受;ADR-0016 本季「禁 MCP 产品码」由本人工决策专项解封(仅本里程碑,不重开版本分支 / live sync)
背景
ADR-0012 将「API/MCP 开放」列为平台级能力:agent 可读 schema、可提交新版本。公开 API 与 MCP server 引入新的鉴权面、速率限制与 scope 模型,不宜与落地页叙事同轮拍板实现。
触发条件现状:落地页 ✅;schema-as-code ✅;需求 = 内部 dogfood + agent 可读事实源(adopt-first)。
决策(已拍板 · adopt-first / MIT)
| 议题 | 决策 |
|---|---|
| 鉴权模型 | Personal Access Token(PAT) + OAuth(client_credentials + Authorization Code/PKCE + refresh_token)+ OIDC(discovery / RS256 id_token + JWKS / userinfo)。PAT 前缀 erd_pat_;OAuth access token 前缀 erd_oat_;refresh 前缀 erd_ort_;auth code 前缀 erd_ac_。均 Authorization: Bearer <token> 调 /api/v1/**(仅 PAT/OAT;refresh 不可直调 API)。会话 JWT 不接受于 /api/v1/**。 |
| OAuth(分切片) | 切片 A(✅):机器对机器 — 注册 confidential client → POST /oauth/token grant_type=client_credentials → 短期 erd_oat_(默认 TTL 3600s)。以注册人身份访问。不签发 refresh / id_token。 切片 B(✅):浏览器 Authorization Code + 强制 PKCE S256 — GET /oauth/authorize(会话 JWT)→ 同意页预览 JSON;产品 UI /oauth/authorize 显式 Allow/Deny;POST decision=allow 才签发 erd_ac_ → POST /oauth/token authorization_code + code_verifier → erd_oat_ + erd_ort_(+ 若 scope 含 openid → id_token)。Deny → error=access_denied。以授权用户身份访问。public client 无 secret;confidential 换票仍须 secret。 post-MVP refresh(✅):仅 auth code 签发 erd_ort_(SHA-256);grant_type=refresh_token 轮换(旧票作废 + 新 access/refresh 同 family_id;含 openid 时重签 id_token);复用已吊销 refresh → 整族吊销;POST /oauth/revoke(RFC 7009 风格)+ 吊销 client 一并失效 refresh。 |
| OIDC(✅)+ nonce/at_hash(✅)+ RS256·JWKS(✅) | GET /.well-known/openid-configuration;issuer=ERD_OIDC_ISSUER 否则 ERD_UI_URL(martin.ui.url 首项)。RS256 id_token(硬切,废 ERD_OIDC_HMAC);密钥:ERD_OIDC_RSA_PRIVATE_KEY(PEM)或 ERD_OIDC_RSA_PRIVATE_KEY_PATH 或 PKCS12(ERD_OIDC_RSA_KEYSTORE_PATH);prod 缺密钥 fail-fast(对齐 JWT_SECRET);非 prod 未配置则自动生成 ~/.erdonline/oidc-rsa-private.pem(仓外)。GET /.well-known/jwks.json 发布公钥 JWK(kid=thumbprint 或 ERD_OIDC_RSA_KID)。GET /oauth/userinfo |