Base Account / Integration

账号系统接入文档

按能力模块拆分的接入规范,供产品工程和 AI Agent 按需获取。

Issuerhttps://user.stringzhao.lifeAudiencebase-account-clientJWKShttps://user.stringzhao.life/.well-known/jwks.jsonDocv2026-03-06.3

Machine Readable Spec

复制 Machine Readable JSON

AI Agent 可直接读取下方 JSON 进行自动接入。结构版本字段为 docVersion。 包含认证系统和邀请码系统的完整规范。

展开查看 Machine Readable JSON
{
  "docVersion": "2026-03-06.3",
  "generatedAt": "2026-03-06.3",
  "service": "base-account-auth",
  "issuer": "https://user.stringzhao.life",
  "audience": "base-account-client",
  "jwksUrl": "https://user.stringzhao.life/.well-known/jwks.json",
  "authorizeContract": {
    "entryPath": "/authorize",
    "requiredQuery": [
      "return_to",
      "state"
    ],
    "optionalQuery": [
      "service (deprecated)"
    ],
    "callbackQuery": [
      "authorized",
      "state"
    ]
  },
  "endpoints": [
    {
      "method": "GET",
      "path": "/authorize",
      "auth": "none",
      "purpose": "统一授权入口。后端基于 return_to 的 origin 识别服务,未登录跳转登录页,已登录则按 consent 状态决定是否直接回跳。可选参数 prompt=select_account:即使已授权,也强制显示账号选择界面(用于多账号切换场景)。",
      "errors": [
        "400 invalid_authorize_request",
        "400 invalid_return_to",
        "400 invalid_service",
        "400 invalid_state"
      ]
    },
    {
      "method": "POST",
      "path": "/api/auth/send-code",
      "auth": "none",
      "purpose": "发送邮箱验证码,返回 requestId。",
      "errors": [
        "400 invalid_input",
        "429 rate_limited",
        "502 email_delivery_failed"
      ]
    },
    {
      "method": "POST",
      "path": "/api/auth/verify-code",
      "auth": "none",
      "purpose": "校验验证码并签发 access/refresh token(同时写入 cookie)。",
      "errors": [
        "400 invalid_code",
        "429 too_many_attempts",
        "403 account_disabled"
      ]
    },
    {
      "method": "POST",
      "path": "/api/auth/authorize/approve",
      "auth": "access_token",
      "purpose": "用户在首次授权页点击同意后写入 consent 记录并返回回跳地址。",
      "errors": [
        "401 missing_access_token",
        "400 invalid_input",
        "400 invalid_return_to",
        "400 invalid_service"
      ]
    },
    {
      "method": "POST",
      "path": "/api/auth/refresh",
      "auth": "refresh_token",
      "purpose": "刷新 access token 和 refresh token。",
      "errors": [
        "401 invalid_refresh_token",
        "400 missing_refresh_token"
      ]
    },
    {
      "method": "POST",
      "path": "/api/auth/logout",
      "auth": "refresh_token",
      "purpose": "注销当前会话并清理 cookie。",
      "errors": [
        "200 幂等,refresh token 失效也可安全调用"
      ]
    },
    {
      "method": "GET",
      "path": "/api/auth/me",
      "auth": "access_token",
      "purpose": "获取当前 access token 对应用户信息。",
      "errors": [
        "401 missing_access_token",
        "401 invalid_access_token"
      ]
    },
    {
      "method": "GET",
      "path": "/.well-known/jwks.json",
      "auth": "none",
      "purpose": "下游服务用于验证 JWT 的公钥集合。",
      "errors": [
        "必须公网可访问,且与 AUTH_ISSUER 保持同源策略"
      ]
    }
  ],
  "integrationSteps": [
    {
      "title": "准备环境变量",
      "detail": "下游服务至少配置 AUTH_ISSUER、AUTH_AUDIENCE、AUTH_JWKS_URL;账号中心配置 AUTH_ALLOWED_RETURN_ORIGINS、AUTH_ALLOWED_RETURN_SUFFIXES。"
    },
    {
      "title": "接入统一授权入口",
      "detail": "外部服务统一跳转 /authorize?return_to&state(service 可传但会被忽略),禁止直接跳 /login。"
    },
    {
      "title": "登记服务域名",
      "detail": "推荐通过 CLI 注册服务:ba admin services create --origin https://your-app.example.com(也可在 Admin Console 的 Services 区域手动登记)。需先登记/启用 origin,再让外部服务发起授权。"
    },
    {
      "title": "处理回跳并建立应用会话",
      "detail": "回跳后在服务端读取共享 access_token cookie 验签 JWT,提取用户 email,然后创建应用自有的 gateway session cookie(HMAC 签名的 email + 过期时间)。重要:不要直接依赖共享 access_token cookie 作为日常登录态,否则跨应用切换账号会导致身份污染。"
    },
    {
      "title": "按需接入 JWT 校验",
      "detail": "如果你的服务需要在后端验签 access token,再接入 auth-sdk 的 JWKS 验签。"
    }
  ],
  "templates": [
    {
      "id": "node-middleware",
      "title": "Node / Express 鉴权中间件",
      "runtime": "Node 20+ / Express"
    },
    {
      "id": "next-route-handler",
      "title": "Next.js Route Handler 保护接口",
      "runtime": "Next.js App Router"
    },
    {
      "id": "frontend-login-flow",
      "title": "前端最小登录流程",
      "runtime": "Browser / SPA"
    },
    {
      "id": "frontend-authorize-entry",
      "title": "外部服务统一授权入口",
      "runtime": "Browser / Web App"
    },
    {
      "id": "frontend-authorize-callback",
      "title": "回跳校验 + 获取用户态(简易版)",
      "runtime": "Browser / Web App"
    },
    {
      "id": "next-gateway-session",
      "title": "Next.js Gateway Session 模式(推荐)",
      "runtime": "Next.js App Router"
    },
    {
      "id": "account-switching",
      "title": "账号切换(多账号场景)",
      "runtime": "Browser / Web App"
    }
  ],
  "checklist": [
    "AUTH_ISSUER 与账号服务域名保持一致(当前: https://user.stringzhao.life)。",
    "AUTH_AUDIENCE 在账号服务和下游服务严格一致(当前: base-account-client)。",
    "AUTH_JWKS_URL 配置为 https://user.stringzhao.life/.well-known/jwks.json。",
    "新接入服务需要先登记并启用 origin。推荐使用 CLI:ba admin services create --origin <url>(也可在 Admin Console -> Services 手动操作)。",
    "/authorize 的 service 参数已弃用(兼容保留,但后端不再依赖该参数判定服务)。",
    "AUTH_ALLOWED_RETURN_ORIGINS 建议至少包含 http://localhost:3000, https://user.stringzhao.life, https://stringzhao.life。",
    "AUTH_ALLOWED_RETURN_SUFFIXES 建议配置为 .stringzhao.life,.vercel.app(一次覆盖你全部 Vercel 服务)。",
    "外部服务统一从 /authorize 进入登录授权流程,不直接拼接 /login。",
    "业务接口对 401/403/429 做显式处理,不把鉴权失败当系统异常。",
    "access_token / refresh_token cookie 在 .stringzhao.life 域共享,任一子域的登录/切换会覆盖所有子域的登录态。接入方应创建应用自有的 gateway session cookie(参考模板),避免跨应用账号污染。",
    "上线后至少做一次 send-code / verify-code / me 全链路回归。"
  ],
  "externalIntegrationChecklist": [
    "授权入口统一改为 /authorize?return_to=<absolute_url>&state=<opaque_state>。",
    "service 参数可传可不传(兼容保留),但不能再用于服务身份判定。",
    "发起授权前生成并持久化 state(建议 randomUUID + sessionStorage)。",
    "回跳后必须校验 authorized=1 且 returned state 与本地 state 完全一致。",
    "每个业务回跳域名(return_to origin)需先开通并启用。推荐使用 CLI:ba admin services create --origin <url>(也可在 /admin -> Services 手动操作)。",
    "回跳后在服务端读取共享 access_token cookie 并验签 JWT(避免前端 CORS),然后创建应用自有的 gateway session cookie 作为日常登录态。不建议直接依赖共享 access_token cookie(跨应用账号污染风险)。",
    "后端 JWT 验签配置保持一致:AUTH_ISSUER、AUTH_AUDIENCE、AUTH_JWKS_URL。",
    "业务侧显式处理 400 invalid_service / 400 invalid_return_to / 401 invalid_access_token。",
    "上线前至少完成首次授权、重复授权直跳、停用服务拦截、icon 展示回退四项回归。",
    "如需账号切换功能,跳转 /authorize 时附加 prompt=select_account 参数。已授权用户将看到账号选择界面,可选择当前账号、历史登录账号或登录新账号。"
  ],
  "invitationCodes": {
    "description": "邀请码系统:每用户每应用可生成 N 个一次性邀请码,兑换后记录邀请关系。",
    "defaultQuota": 3,
    "endpoints": [
      {
        "method": "POST",
        "path": "/api/auth/invitation-codes/generate",
        "auth": "access_token",
        "purpose": "为当前用户在指定应用下生成一个一次性邀请码。每用户每应用有配额限制(普通用户默认 3,管理员 1000)。serviceKey 需先通过 CLI 注册:ba admin services create --origin <url>。",
        "errors": [
          "401 missing_access_token",
          "400 invalid_input",
          "400 invalid_service",
          "403 invitation_quota_exceeded"
        ]
      },
      {
        "method": "POST",
        "path": "/api/auth/invitation-codes/redeem",
        "auth": "access_token",
        "purpose": "兑换邀请码。仅需传入 code,无需 serviceKey(系统自动从邀请码记录中读取)。一次性使用,兑换后记录邀请关系(谁邀请了谁)。普通用户不能兑换自己生成的邀请码;管理员账号可用于自助开通。服务代理模式:使用 API key 认证时可传入 userId 代表终端用户兑换,适用于下游服务有独立 session 的场景。",
        "errors": [
          "401 missing_access_token",
          "400 invalid_invitation_code",
          "400 self_redeem_not_allowed",
          "409 invitation_code_already_redeemed"
        ]
      },
      {
        "method": "POST",
        "path": "/api/auth/invitation-codes/validate",
        "auth": "access_token",
        "purpose": "仅校验邀请码有效性,不消费。仅需传入 code,无需 serviceKey。适用于前端实时校验场景。",
        "errors": [
          "401 missing_access_token",
          "400 invalid_input"
        ]
      },
      {
        "method": "GET",
        "path": "/api/auth/invitation-codes?serviceKey=my-app",
        "auth": "access_token",
        "purpose": "列出当前用户在指定应用下生成的所有邀请码及配额信息。",
        "errors": [
          "401 missing_access_token",
          "400 invalid_input"
        ]
      },
      {
        "method": "POST",
        "path": "/api/auth/invitation-codes/revoke",
        "auth": "access_token",
        "purpose": "撤销自己生成的 ACTIVE 状态邀请码。已兑换的码不可撤销。",
        "errors": [
          "401 missing_access_token",
          "404 invitation_code_not_found",
          "403 forbidden",
          "400 invalid_invitation_code"
        ]
      }
    ],
    "integrationSteps": [
      {
        "title": "生成邀请码",
        "detail": "已登录用户调用 POST /api/auth/invitation-codes/generate,传入 serviceKey,获得 8 位邀请码。每用户每应用默认可生成 3 个(管理员配额为 1000)。serviceKey 需先通过 CLI 注册服务:ba admin services create --origin https://your-app.example.com。"
      },
      {
        "title": "分享邀请码",
        "detail": "将邀请码通过任意渠道(聊天、邮件、社交媒体等)发送给受邀人。"
      },
      {
        "title": "受邀人兑换",
        "detail": "受邀人登录后调用 POST /api/auth/invitation-codes/redeem,仅需传入 code(不需要 serviceKey)。系统自动从邀请码记录中读取 serviceKey,记录邀请关系并返回 serviceKey 和邀请者 ID。"
      },
      {
        "title": "下游业务处理",
        "detail": "下游服务根据 redeem 返回的 serviceKey + creatorId 决定后续动作(如:解锁功能、发放奖励、建立推荐关系等)。"
      }
    ]
  }
}