accounts/docs/api/auth.md
2026-04-14 16:32:15 +08:00

514 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Authentication And Authorization / 认证与鉴权
## 中文
### 当前认证模型
`accounts.svc.plus` 不是“纯 JWT API”而是
- 以 session token 为主控制面事实来源。
-`xc_session` cookie 和 `Authorization: Bearer <session-token>` 为主调用方式。
-`auth.enable` 打开时,为部分路由叠加 JWT middleware。
-`/api/internal/*` 使用 internal service token。
-`/api/agent-server/v1/users|status` 使用 agent token。
这意味着“JWT 已启用”并不等于“业务只靠 JWT 运行”;很多 handler 仍会继续读取 session。
### 认证方式总表
| 方式 | 典型接口 | 传入位置 | 成功后得到什么 |
| --- | --- | --- | --- |
| Session token | `/api/auth/login` `/api/auth/session` `/api/auth/xworkmate/*` | `Authorization``xc_session` cookie | 当前用户上下文、管理员权限、XWorkmate profile 读写能力。 |
| JWT refresh | `POST /api/auth/token/refresh` | JSON body `refresh_token` | 新 `access_token`。 |
| OAuth exchange code | `POST /api/auth/token/exchange` | JSON body `exchange_code` | 真实 session token字段名同时以 `token` / `access_token` 返回。 |
| Internal service token | `/api/internal/*` | `Authorization: Bearer <token>` | 受信任服务读接口。 |
| Agent token | `/api/agent-server/v1/users` `/api/agent-server/v1/status` | `Authorization: Bearer <token>` | Agent 身份、client 列表拉取、状态上报。 |
### Session issuance paths
以下路径会签发新的 session token
| 入口 | 请求字段 | 成功返回 | 备注 |
| --- | --- | --- | --- |
| `POST /api/auth/login` | `identifier/account/username/email` + `password`,或邮箱 + `totpCode` | `message`、`token`、`access_token`、`expiresAt`、`expires_in`、`user` | 如果用户已启用 MFA 且未提交验证码,则不会发 session而是先返回 MFA challenge。 |
| `POST /api/auth/register/verify` | `email`、`code` | `message`、`token`、`expiresAt`、`user` 或 `verified=true` | 已创建用户走“验证邮箱并自动登录”;预注册验证码走“仅标记 verified”。 |
| `POST /api/auth/password/reset/confirm` | `token`、`password` | `message`、`token`、`expiresAt`、`user` | 重置密码成功后直接进入新会话。 |
| `POST /api/auth/mfa/verify` | `mfa_ticket/mfaToken`、`code/totpCode` | `message`、`token`、`access_token`、`expiresAt`、`expires_in`、`user` | 登录后补做 MFA 的完成步骤。 |
| `POST /api/auth/mfa/totp/verify` | `token`、`code` | `message`、`token`、`expiresAt`、`user` | 首次启用 TOTP 成功后直接签发 session。 |
| `GET /api/auth/oauth/callback/:provider` | query `code` | `307` redirect 到前端 `/login?exchange_code=...` | callback 自身不直接输出 JSON而是先创建 session再下发一次性 exchange code。 |
### 注册与邮箱验证
#### `POST /api/auth/register/send`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `email` |
| 成功返回 | `200 {"message":"verification email sent"}` |
| 前置条件 | 邮箱格式合法;不在 blacklist若邮箱已存在且未验证则继续发送验证邮件。 |
| 失败返回 | `invalid_request`、`invalid_email`、`email_blacklisted`、`smtp_timeout`、`verification_failed`、`email_already_exists`。 |
#### `POST /api/auth/register`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `name`、`email`、`password`、`code` |
| 成功返回 | `201 {"message":"registration successful","user":...}` |
| 前置条件 | `name` 非空;邮箱合法;密码长度至少 8若启用邮箱验证则 `code` 必须存在且匹配。 |
| 关键副作用 | 创建 `store.User`;自动 upsert 7 天 trial `store.Subscription`。 |
| 失败返回 | `name_required`、`missing_credentials`、`invalid_email`、`password_too_short`、`verification_required`、`invalid_code`、`email_already_exists`、`name_already_exists`。 |
#### `POST /api/auth/register/verify`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `email`、`code` |
| 成功返回 A | `200 {"message":"email verified","token":"...","expiresAt":"...","user":...}` |
| 成功返回 B | `200 {"message":"verification successful","verified":true}` |
| 分支解释 | 若命中已创建用户的 email verification接口会把用户标记为已验证并直接签发 session若命中注册前验证码只做“验证码通过”标记。 |
| 失败返回 | `token_in_query`、`invalid_request`、`invalid_code`、`verification_failed`、`session_creation_failed`。 |
### 登录、MFA challenge 与会话读取
#### `POST /api/auth/login`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `identifier`、`account`、`username`、`email`、`password`、`totpCode` |
| 标准成功返回 | `message`、`token`、`access_token`、`expiresAt`、`expires_in`、`mfaRequired=false`、`user` |
| MFA challenge 返回 | `message="mfa required"`、`mfaRequired=true`、`mfaMethod="totp"`、`mfaTicket`、`mfa_ticket`、兼容字段 `mfaToken` |
| 真实规则 | 先按 `identifier -> account -> username -> email` 解析登录标识。若用户已启用 MFA 但未提交 `totpCode`,登录不发 session只发 challenge。 |
| 失败返回 | `credentials_in_query`、`invalid_request`、`missing_credentials`、`user_not_found`、`invalid_credentials`、`password_required`、`email_not_verified`、`sandbox_no_login`、`mfa_challenge_creation_failed`。 |
#### `POST /api/auth/mfa/verify`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `mfa_ticket`、`mfaToken`、`code`、`totpCode`、`method` |
| 成功返回 | `message`、`token`、`access_token`、`expiresAt`、`expires_in`、`user` |
| 前置条件 | `method` 仅支持 `totp`ticket 必须存在且未过期;用户已启用 MFA。 |
| 失败返回 | `mfa_ticket_required`、`mfa_code_required`、`unsupported_mfa_method`、`invalid_mfa_ticket`、`mfa_not_enabled`、`invalid_mfa_code`。 |
#### `GET /api/auth/session`
| 项 | 内容 |
| --- | --- |
| 认证 | 需要有效 session若启用 token middleware还会先经过 JWT + active-user 检查。 |
| 成功返回 | `{"user": ...}`,其中可能附带 `tenantId`、`tenants`、XWorkmate access 视图。 |
| 失败返回 | `session_token_required`、`invalid_session`、`session_user_lookup_failed`、`account_suspended`。 |
#### `DELETE /api/auth/session`
| 项 | 内容 |
| --- | --- |
| 认证 | 需要有效 session。 |
| 成功返回 | `204 No Content` |
| 副作用 | 删除进程内 session并清空 cookie。 |
### TOTP 启用、查询与关闭
#### `POST /api/auth/mfa/totp/provision`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `token`、`issuer`、`account` |
| 成功返回 | `secret`、`otpauth_url`、`issuer`、`account`、`mfaToken`、`mfa`、`user` |
| 入口模式 | 可使用已有 `mfa token`,也可使用当前 session 自动创建新的 MFA challenge。 |
| 失败返回 | `invalid_request`、`invalid_mfa_token`、`mfa_token_required`、`invalid_session`、`mfa_already_enabled`、`read_only_account`、`mfa_secret_generation_failed`、`mfa_setup_failed`。 |
#### `POST /api/auth/mfa/totp/verify`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `token`、`code` |
| 成功返回 | `{"message":"mfa_verified","token":"...","expiresAt":"...","user":...}` |
| 特殊失败 | 多次错误会进入 `429 {"error":"mfa_challenge_locked","retryAt":"...","mfaToken":"..."}`。 |
| 常见失败 | `mfa_token_required`、`invalid_mfa_token`、`mfa_secret_missing`、`mfa_code_required`、`invalid_mfa_code`、`mfa_update_failed`。 |
#### `GET /api/auth/mfa/status`
| 项 | 内容 |
| --- | --- |
| 输入来源 | query `token` / `identifier` / `email`header `X-MFA-Token`,或 `Authorization` session token。 |
| 成功返回 | `enabled`、`mfa`、`user`。若按 identifier 查询且用户不存在,返回 `200 {"mfa_enabled":false}`。 |
| 失败返回 | `mfa_status_failed`、`mfa_token_required`。 |
#### `POST /api/auth/mfa/disable`
| 项 | 内容 |
| --- | --- |
| 认证 | 当前 session token优先从 `Authorization` 读取,也接受 query `token`。 |
| 成功返回 | `{"message":"mfa_disabled","user":...}` |
| 失败返回 | `session_token_required`、`invalid_session`、`mfa_disable_failed`、`mfa_not_enabled`、`read_only_account`。 |
### OAuth 与 exchange code
#### `GET /api/auth/oauth/login/:provider`
| 项 | 内容 |
| --- | --- |
| 路径参数 | `provider`,当前实现支持 `github``google`。 |
| 成功返回 | `307 Temporary Redirect` 到 provider authorization URL。 |
| 失败返回 | `provider_not_found`。 |
#### `GET /api/auth/oauth/callback/:provider`
| 项 | 内容 |
| --- | --- |
| 输入 | query `code`,可选由 `state` 带回前端 URL。 |
| 成功行为 | 交换 provider token拉取 profile创建或复用用户确保 `store.Identity` 绑定,然后签发 session + 一次性 exchange code最后 `307` 跳转到前端 `/login?exchange_code=...`。 |
| 失败返回 | `provider_not_found`、`code_missing`、`oauth_exchange_failed`、`fetch_profile_failed`、`email_missing`、`email_not_verified`、`store_error`、`user_creation_failed`、`session_creation_failed`、`exchange_code_creation_failed`。 |
#### `POST /api/auth/token/exchange`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `exchange_code` |
| 成功返回 | `token`、`access_token`、`token_type`、`expiresAt`、`expires_in`、`user` |
| 语义 | 不是按 user claims 自签 token而是把 callback 阶段暂存的一次性 code 换回真实 session。 |
| 失败返回 | `invalid_request`、`invalid_exchange_code`、`session_user_lookup_failed`。 |
### JWT refresh
#### `POST /api/auth/token/refresh`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `refresh_token` |
| 成功返回 | `access_token`、`token_type="Bearer"`、`expires_in` |
| 前置条件 | `h.tokenService != nil`refresh token 合法且未过期。 |
| 失败返回 | `token_service_unavailable`、`invalid_request`、`invalid_refresh_token`。 |
#### `POST /api/auth/refresh`
别名路由,行为与 `POST /api/auth/token/refresh` 完全一致。
### 密码重置
#### `POST /api/auth/password/reset`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `email` |
| 成功返回 | `202 {"message":"if the account exists a reset email will be sent"}` |
| 实现说明 | handler 本身按邮箱驱动;但该路由被挂在 authProtected 组下,因此启用 JWT middleware 后会多一层前置认证。 |
| 失败返回 | `email_in_query`、`invalid_request`、`email_required`、`password_reset_failed`、`read_only_account`。 |
#### `POST /api/auth/password/reset/confirm`
| 项 | 内容 |
| --- | --- |
| 请求字段 | `token`、`password` |
| 成功返回 | `message`、`token`、`expiresAt`、`user` |
| 前置条件 | password 长度至少 8reset token 有效;若用户是 demo/read-only account 则拒绝。 |
| 失败返回 | `credentials_in_query`、`invalid_request`、`password_too_short`、`invalid_token`、`password_reset_failed`、`read_only_account`、`session_creation_failed`。 |
### XWorkmate profile 与 Vault-backed secrets
#### `GET /api/auth/xworkmate/profile`
| 项 | 内容 |
| --- | --- |
| 成功返回 | `edition`、`tenant`、`membershipRole`、`profileScope`、`canEditIntegrations`、`canManageTenant`、`profile`、`tokenConfigured` |
| profile 字段 | `BRIDGE_SERVER_URL`、`bridgeServerOrigin`、`vaultUrl`、`vaultNamespace`、`vaultSecretPath`、`vaultSecretKey`、`secretLocators`、`apisixUrl` |
| 失败返回 | `tenant_membership_required`、`tenant_not_found`、`xworkmate_context_failed`、`xworkmate_profile_read_failed`。 |
#### `GET /api/auth/xworkmate/profile/sync`
| 项 | 内容 |
| --- | --- |
| 成功返回 | `BRIDGE_SERVER_URL`、`BRIDGE_AUTH_TOKEN` |
| 语义 | 给 bridge / desktop sync 使用的精简同步视图,不返回完整 profile。 |
| 失败返回 | `tenant_membership_required`、`tenant_not_found`、`bridge_server_url_unavailable`、`bridge_auth_token_unavailable`。 |
#### `PUT /api/auth/xworkmate/profile`
| 项 | 内容 |
| --- | --- |
| 请求字段 | 允许直接传 profile payload`{ "profile": {...} }` |
| 禁止字段 | raw token/password/api key 不允许持久化;命中时返回 `token_persistence_forbidden`。 |
| 成功返回 | 与 `GET /xworkmate/profile` 同形。 |
| 失败返回 | `xworkmate_profile_forbidden`、`read_only_account`、`invalid_request`、`token_persistence_forbidden`、`xworkmate_profile_write_failed`。 |
#### `GET /api/auth/xworkmate/secrets`
| 项 | 内容 |
| --- | --- |
| 成功返回 | `tenant`、`membershipRole`、`profileScope`、`canEditIntegrations`、`vaultBackendEnabled`、`tokenConfigured`、`secrets` |
| `secrets[]` 元素 | `target`、`provider`、`secretPath`、`secretKey`、`configured`、`required` 等元数据;绝不返回 raw secret。 |
| 失败返回 | `xworkmate_secret_read_failed`、`xworkmate_context_failed`、`tenant_not_found`。 |
#### `PUT /api/auth/xworkmate/secrets/:target`
| 项 | 内容 |
| --- | --- |
| 路径参数 | `target`,例如 bridge auth token 对应的 secret target。 |
| 请求字段 | `value` |
| 成功返回 | `secret`、`profileScope`、`tokenConfigured` |
| 失败返回 | `xworkmate_secret_forbidden`、`read_only_account`、`xworkmate_secret_unknown_target`、`xworkmate_secret_value_required`、`xworkmate_secret_write_failed`、`xworkmate_profile_write_failed`。 |
#### `DELETE /api/auth/xworkmate/secrets/:target`
| 项 | 内容 |
| --- | --- |
| 路径参数 | `target` |
| 成功返回 | `secret`、`profileScope`、`tokenConfigured` |
| 语义 | 删除 Vault/backend secret但保留 locator 元数据。 |
| 失败返回 | `xworkmate_secret_forbidden`、`read_only_account`、`xworkmate_secret_unknown_target`、`xworkmate_secret_delete_failed`。 |
## English
### Current Auth Model
`accounts.svc.plus` is not a pure JWT API. It is:
- session-first for the current control plane,
- primarily called through the `xc_session` cookie or `Authorization: Bearer <session-token>`,
- optionally wrapped by JWT middleware when `auth.enable` is on,
- protected by an internal service token for `/api/internal/*`,
- and protected by agent tokens for `/api/agent-server/v1/users|status`.
So “JWT enabled” does not mean “business logic runs only on JWT”; many handlers still resolve sessions explicitly.
### Authentication Modes
| Mode | Example APIs | Input location | Successful outcome |
| --- | --- | --- | --- |
| Session token | `/api/auth/login`, `/api/auth/session`, `/api/auth/xworkmate/*` | `Authorization` header or `xc_session` cookie | User context, admin permissions, XWorkmate profile access. |
| JWT refresh | `POST /api/auth/token/refresh` | JSON body `refresh_token` | A new `access_token`. |
| OAuth exchange code | `POST /api/auth/token/exchange` | JSON body `exchange_code` | The real session token, returned in both `token` and `access_token`. |
| Internal service token | `/api/internal/*` | `Authorization: Bearer <token>` | Trusted service-to-service reads. |
| Agent token | `/api/agent-server/v1/users`, `/api/agent-server/v1/status` | `Authorization: Bearer <token>` | Agent identity, client-list reads, status reporting. |
### Session Issuance Paths
The following flows mint a new session token:
| Entry point | Request fields | Success shape | Notes |
| --- | --- | --- | --- |
| `POST /api/auth/login` | `identifier/account/username/email` plus `password`, or email plus `totpCode` | `message`, `token`, `access_token`, `expiresAt`, `expires_in`, `user` | If MFA is enabled and no TOTP code is provided, the handler returns an MFA challenge instead of a session. |
| `POST /api/auth/register/verify` | `email`, `code` | `message`, `token`, `expiresAt`, `user` or `verified=true` | Existing-user email verification auto-logs the user in; pre-registration verification only marks the email as verified. |
| `POST /api/auth/password/reset/confirm` | `token`, `password` | `message`, `token`, `expiresAt`, `user` | A successful password reset immediately creates a session. |
| `POST /api/auth/mfa/verify` | `mfa_ticket/mfaToken`, `code/totpCode` | `message`, `token`, `access_token`, `expiresAt`, `expires_in`, `user` | Completes the MFA step after login. |
| `POST /api/auth/mfa/totp/verify` | `token`, `code` | `message`, `token`, `expiresAt`, `user` | First-time TOTP enablement also ends with a new session. |
| `GET /api/auth/oauth/callback/:provider` | query `code` | `307` redirect to frontend `/login?exchange_code=...` | The callback creates the session first, then issues a one-time exchange code instead of returning JSON directly. |
### Registration And Email Verification
#### `POST /api/auth/register/send`
| Item | Details |
| --- | --- |
| Request fields | `email` |
| Success | `200 {"message":"verification email sent"}` |
| Preconditions | Valid email format; not blacklisted; existing unverified users can still receive verification mail. |
| Failures | `invalid_request`, `invalid_email`, `email_blacklisted`, `smtp_timeout`, `verification_failed`, `email_already_exists`. |
#### `POST /api/auth/register`
| Item | Details |
| --- | --- |
| Request fields | `name`, `email`, `password`, `code` |
| Success | `201 {"message":"registration successful","user":...}` |
| Preconditions | Non-empty `name`; valid email; password length at least 8; when email verification is enabled, `code` must exist and match. |
| Side effects | Creates `store.User` and upserts a 7-day trial `store.Subscription`. |
| Failures | `name_required`, `missing_credentials`, `invalid_email`, `password_too_short`, `verification_required`, `invalid_code`, `email_already_exists`, `name_already_exists`. |
#### `POST /api/auth/register/verify`
| Item | Details |
| --- | --- |
| Request fields | `email`, `code` |
| Success A | `200 {"message":"email verified","token":"...","expiresAt":"...","user":...}` |
| Success B | `200 {"message":"verification successful","verified":true}` |
| Branching | Existing-user verification marks the user as verified and issues a session; pre-registration verification only confirms the code. |
| Failures | `token_in_query`, `invalid_request`, `invalid_code`, `verification_failed`, `session_creation_failed`. |
### Login, MFA Challenge, And Session Reads
#### `POST /api/auth/login`
| Item | Details |
| --- | --- |
| Request fields | `identifier`, `account`, `username`, `email`, `password`, `totpCode` |
| Standard success | `message`, `token`, `access_token`, `expiresAt`, `expires_in`, `mfaRequired=false`, `user` |
| MFA challenge | `message="mfa required"`, `mfaRequired=true`, `mfaMethod="totp"`, `mfaTicket`, `mfa_ticket`, compatibility field `mfaToken` |
| Behavior | Identifier resolution order is `identifier -> account -> username -> email`. If MFA is enabled and no TOTP code is provided, the handler returns a challenge instead of a session. |
| Failures | `credentials_in_query`, `invalid_request`, `missing_credentials`, `user_not_found`, `invalid_credentials`, `password_required`, `email_not_verified`, `sandbox_no_login`, `mfa_challenge_creation_failed`. |
#### `POST /api/auth/mfa/verify`
| Item | Details |
| --- | --- |
| Request fields | `mfa_ticket`, `mfaToken`, `code`, `totpCode`, `method` |
| Success | `message`, `token`, `access_token`, `expiresAt`, `expires_in`, `user` |
| Preconditions | Only `totp` is supported; the ticket must exist and not be expired; the user must have MFA enabled. |
| Failures | `mfa_ticket_required`, `mfa_code_required`, `unsupported_mfa_method`, `invalid_mfa_ticket`, `mfa_not_enabled`, `invalid_mfa_code`. |
#### `GET /api/auth/session`
| Item | Details |
| --- | --- |
| Auth | Requires a valid session. If token middleware is enabled, the request also passes JWT + active-user checks first. |
| Success | `{"user": ...}` and may include `tenantId`, `tenants`, and XWorkmate access metadata. |
| Failures | `session_token_required`, `invalid_session`, `session_user_lookup_failed`, `account_suspended`. |
#### `DELETE /api/auth/session`
| Item | Details |
| --- | --- |
| Auth | Requires a valid session. |
| Success | `204 No Content` |
| Side effect | Removes the process-local session and clears the cookie. |
### TOTP Provisioning, Status, And Disable
#### `POST /api/auth/mfa/totp/provision`
| Item | Details |
| --- | --- |
| Request fields | `token`, `issuer`, `account` |
| Success | `secret`, `otpauth_url`, `issuer`, `account`, `mfaToken`, `mfa`, `user` |
| Entry modes | Uses an existing MFA token or can bootstrap a new MFA challenge from the current session. |
| Failures | `invalid_request`, `invalid_mfa_token`, `mfa_token_required`, `invalid_session`, `mfa_already_enabled`, `read_only_account`, `mfa_secret_generation_failed`, `mfa_setup_failed`. |
#### `POST /api/auth/mfa/totp/verify`
| Item | Details |
| --- | --- |
| Request fields | `token`, `code` |
| Success | `{"message":"mfa_verified","token":"...","expiresAt":"...","user":...}` |
| Special failure | Repeated failures can lock the challenge and return `429 {"error":"mfa_challenge_locked","retryAt":"...","mfaToken":"..."}`. |
| Common failures | `mfa_token_required`, `invalid_mfa_token`, `mfa_secret_missing`, `mfa_code_required`, `invalid_mfa_code`, `mfa_update_failed`. |
#### `GET /api/auth/mfa/status`
| Item | Details |
| --- | --- |
| Inputs | query `token` / `identifier` / `email`, header `X-MFA-Token`, or `Authorization` session token. |
| Success | `enabled`, `mfa`, `user`. If queried by identifier and the user does not exist, it returns `200 {"mfa_enabled":false}`. |
| Failures | `mfa_status_failed`, `mfa_token_required`. |
#### `POST /api/auth/mfa/disable`
| Item | Details |
| --- | --- |
| Auth | Current session token, preferably from `Authorization`; also accepts query `token`. |
| Success | `{"message":"mfa_disabled","user":...}` |
| Failures | `session_token_required`, `invalid_session`, `mfa_disable_failed`, `mfa_not_enabled`, `read_only_account`. |
### OAuth And Exchange Code
#### `GET /api/auth/oauth/login/:provider`
| Item | Details |
| --- | --- |
| Path param | `provider`; the current code supports `github` and `google`. |
| Success | `307 Temporary Redirect` to the provider authorization URL. |
| Failure | `provider_not_found`. |
#### `GET /api/auth/oauth/callback/:provider`
| Item | Details |
| --- | --- |
| Input | query `code`; the `state` value may carry a frontend URL. |
| Success behavior | Exchanges the provider code, fetches the profile, creates or reuses the user, ensures the `store.Identity` binding exists, issues a session plus a one-time exchange code, then redirects to the frontend `/login?exchange_code=...`. |
| Failures | `provider_not_found`, `code_missing`, `oauth_exchange_failed`, `fetch_profile_failed`, `email_missing`, `email_not_verified`, `store_error`, `user_creation_failed`, `session_creation_failed`, `exchange_code_creation_failed`. |
#### `POST /api/auth/token/exchange`
| Item | Details |
| --- | --- |
| Request fields | `exchange_code` |
| Success | `token`, `access_token`, `token_type`, `expiresAt`, `expires_in`, `user` |
| Semantics | This does not mint a token from caller-provided claims. It converts the one-time code created during the OAuth callback back into the real session. |
| Failures | `invalid_request`, `invalid_exchange_code`, `session_user_lookup_failed`. |
### JWT Refresh
#### `POST /api/auth/token/refresh`
| Item | Details |
| --- | --- |
| Request fields | `refresh_token` |
| Success | `access_token`, `token_type="Bearer"`, `expires_in` |
| Preconditions | `h.tokenService != nil`; the refresh token must be valid and not expired. |
| Failures | `token_service_unavailable`, `invalid_request`, `invalid_refresh_token`. |
#### `POST /api/auth/refresh`
Alias route with the exact same behavior as `POST /api/auth/token/refresh`.
### Password Reset
#### `POST /api/auth/password/reset`
| Item | Details |
| --- | --- |
| Request fields | `email` |
| Success | `202 {"message":"if the account exists a reset email will be sent"}` |
| Implementation note | The handler itself is email-driven, but the route is mounted under the protected auth group, so enabling JWT middleware adds an extra precondition. |
| Failures | `email_in_query`, `invalid_request`, `email_required`, `password_reset_failed`, `read_only_account`. |
#### `POST /api/auth/password/reset/confirm`
| Item | Details |
| --- | --- |
| Request fields | `token`, `password` |
| Success | `message`, `token`, `expiresAt`, `user` |
| Preconditions | Password length at least 8; reset token must be valid; demo/read-only users are rejected. |
| Failures | `credentials_in_query`, `invalid_request`, `password_too_short`, `invalid_token`, `password_reset_failed`, `read_only_account`, `session_creation_failed`. |
### XWorkmate Profile And Vault-Backed Secrets
#### `GET /api/auth/xworkmate/profile`
| Item | Details |
| --- | --- |
| Success | `edition`, `tenant`, `membershipRole`, `profileScope`, `canEditIntegrations`, `canManageTenant`, `profile`, `tokenConfigured` |
| `profile` fields | `BRIDGE_SERVER_URL`, `bridgeServerOrigin`, `vaultUrl`, `vaultNamespace`, `vaultSecretPath`, `vaultSecretKey`, `secretLocators`, `apisixUrl` |
| Failures | `tenant_membership_required`, `tenant_not_found`, `xworkmate_context_failed`, `xworkmate_profile_read_failed`. |
#### `GET /api/auth/xworkmate/profile/sync`
| Item | Details |
| --- | --- |
| Success | `BRIDGE_SERVER_URL`, `BRIDGE_AUTH_TOKEN` |
| Semantics | A reduced sync view used by bridge / desktop flows instead of the full profile. |
| Failures | `tenant_membership_required`, `tenant_not_found`, `bridge_server_url_unavailable`, `bridge_auth_token_unavailable`. |
#### `PUT /api/auth/xworkmate/profile`
| Item | Details |
| --- | --- |
| Request fields | Accepts either a raw profile payload or `{ "profile": {...} }` |
| Forbidden fields | Raw token/password/api-key persistence is rejected with `token_persistence_forbidden`. |
| Success | Same shape as `GET /xworkmate/profile`. |
| Failures | `xworkmate_profile_forbidden`, `read_only_account`, `invalid_request`, `token_persistence_forbidden`, `xworkmate_profile_write_failed`. |
#### `GET /api/auth/xworkmate/secrets`
| Item | Details |
| --- | --- |
| Success | `tenant`, `membershipRole`, `profileScope`, `canEditIntegrations`, `vaultBackendEnabled`, `tokenConfigured`, `secrets` |
| `secrets[]` | Contains `target`, `provider`, `secretPath`, `secretKey`, `configured`, `required`, and similar metadata. It never returns the raw secret value. |
| Failures | `xworkmate_secret_read_failed`, `xworkmate_context_failed`, `tenant_not_found`. |
#### `PUT /api/auth/xworkmate/secrets/:target`
| Item | Details |
| --- | --- |
| Path param | `target`, for example the bridge-auth-token secret target. |
| Request fields | `value` |
| Success | `secret`, `profileScope`, `tokenConfigured` |
| Failures | `xworkmate_secret_forbidden`, `read_only_account`, `xworkmate_secret_unknown_target`, `xworkmate_secret_value_required`, `xworkmate_secret_write_failed`, `xworkmate_profile_write_failed`. |
#### `DELETE /api/auth/xworkmate/secrets/:target`
| Item | Details |
| --- | --- |
| Path param | `target` |
| Success | `secret`, `profileScope`, `tokenConfigured` |
| Semantics | Deletes the Vault/backend secret while preserving locator metadata. |
| Failures | `xworkmate_secret_forbidden`, `read_only_account`, `xworkmate_secret_unknown_target`, `xworkmate_secret_delete_failed`. |