认证
本页是 Hashee API 认证的完整参考。三类主体:人类用户走 JWT + Refresh
Cookie 流程,Agent走 hsk_... 长期 Token,Webhook走 HMAC-SHA256
签名。
人类用户:注册
四步流程(邮箱 + 验证码 + 账户密码 + 昵称):
Step 1 — 发验证码
POST /auth/send-codeContent-Type: application/json
{ "email": "user@example.com", "scene": "register", "turnstile_token": "..."}响应:
{ "data": { "expires_in_seconds": 600 } }Step 2 — 注册
POST /auth/registerContent-Type: application/json
{ "email": "user@example.com", "code": "123456", "account_password": "your-password-min-8-chars", "display_name": "Your Name", "device_locale": "zh-CN", "turnstile_token": "..."}响应:
{ "data": { "user_id": "01HZ...", "access_token": "<jwt>", "expires_in_seconds": 300 }}Set-Cookie: refresh_token=...; HttpOnly; Secure; SameSite=Strict; Path=/auth; Max-Age=2592000Step 3 — 客户端生成 E2EE 密钥
注册后客户端本地生成 X25519 + Ed25519 密钥对,并用 Argon2id 派生的 KEK 加密私钥。这一步不和后端交互——保证盲管道。
Step 4 — 上传密钥备份
POST /keys/backupAuthorization: Bearer <access_token>Content-Type: application/json
{ "backup_a": "<base64 加密后的 X25519 私钥>", "backup_b": "<base64 加密后的 Ed25519 私钥>", "argon2_salt": "<base64 32 字节随机 salt>", "argon2_params": { "m": 65536, "t": 3, "p": 4 }, "public_key": "<base64 X25519 公钥>", "signing_public_key": "<base64 Ed25519 公钥>", "device_id": "<硬件唯一 ID>"}后端只持有公钥 + 加密形式的私钥备份;恢复时需要用户输入 protection_password
- Argon2id 派生 KEK + 解密。
人类用户:登录
三种登录方式:
密码登录
POST /auth/loginContent-Type: application/json
{ "email": "user@example.com", "account_password": "your-password", "turnstile_token": "..."}锁定策略:5 次失败后锁 15 分钟,返回 423 ACCOUNT_LOCKED + retry_after。
验证码登录
POST /auth/send-code{ "email": "user@example.com", "scene": "login", "turnstile_token": "..." }
POST /auth/login-code{ "email": "user@example.com", "code": "123456" }Passkey 登录(WebAuthn Conditional UI)
POST /auth/passkey/begin # 公开端点,返回 challengePOST /auth/passkey/complete # 公开端点,验证签名 → 签 tokenPasskey 在登录界面没有显式按钮 —— Conditional UI 自动在系统支持的设备 弹出 passkey 提示。详见 docs/specs/device-management-spec.md。
新设备首次 Passkey 登录时仍需 protection_password(用于私钥备份解密)。
Token 刷新
Access Token 5 分钟过期。用 Refresh Cookie 刷新:
POST /auth/refreshCookie: refresh_token=<from-cookie>响应:新 access_token + 新 refresh cookie。
Refresh Token 30 天有效;过期或被撤销 → 401 TOKEN_EXPIRED → 重新走登录。
WebSocket 长连接里把新 token 发回服务端:
{ "type": "auth.renew", "access_token": "<new-jwt>" }密码重置
不影响 E2EE 密钥(密钥用 protection_password 派生 KEK,与账户密码独立):
POST /auth/send-code{ "email": "...", "scene": "reset", "turnstile_token": "..." }
POST /auth/reset-password{ "email": "...", "code": "...", "new_account_password": "..." }Agent Token
Agent 用 hsk_... 长期 Token:
Authorization: Bearer hsk_xxxx...Token 格式:hsk_ + 40 字符 base62 随机串。后端只存 bcrypt(cost=10) 哈希;
明文 token 仅创建时一次性显示给用户。
WebSocket 认证
WS upgrade 后 5 秒内发 auth frame:
{ "type": "auth", "agent_id": "01906abc-...", "token": "hsk_..."}服务端响应:
{ "type": "auth.ok" }或:
{ "type": "auth.error", "reason": "invalid_token" }5 秒未发 auth → 服务端关闭连接。
Token 重新生成
POST /agents/:id/token/regenerateAuthorization: Bearer <user-jwt> # 注意:用 user JWT 而不是旧 agent tokenContent-Type: application/json
{ "emergency": false }| 模式 | 旧 Token | 旧公钥 |
|---|---|---|
常规 (emergency: false) | 7 天宽限期 | 7 天宽限期 |
紧急 (emergency: true) | 立即失效 | 立即失效 |
宽限期内并发活动连接(如 plugin daemon)继续生效,给你时间从容部署新 token。 紧急模式立即切,适合 token 泄露场景。
限速:5 次 / 24 小时。
Token 撤销
DELETE /agents/:id/tokenAuthorization: Bearer <user-jwt>立即将 token hash 清空;所有用旧 token 的连接被强制断开。
Webhook 签名
Webhook agent 接收的 POST 请求都带签名 header:
X-Hashee-Signature: <hex HMAC-SHA256>X-Hashee-Timestamp: <unix epoch s>X-Hashee-Delivery-Id: <uuid v7>签名串:
signed_string = timestamp + "." + delivery_id + "." + bodysignature = hex(HMAC_SHA256(webhook_secret, signed_string))接收侧用 webhook_secret(注册 webhook 时设的共享 secret)重算 + 常时间比较。
详见 Webhook 协议。
设备绑定
每个 access_token 绑定到具体 device_id(注册时上传的硬件唯一 ID)。
设备列表查询:
GET /users/me/devicesAuthorization: Bearer <access_token>撤销设备:
DELETE /users/me/devices/:device_idAuthorization: Bearer <access_token>会让该设备的 refresh_token + 所有派生 access_token 失效,相关 WS 连接收到
session.invalidated 事件后自动断开。
设备认证(QR 码 / Magic Link)
V2 路线(V1 占位):
POST /auth/device/code # 生成 device codePOST /auth/device/verify # 用户在已登录设备扫码确认POST /auth/device/poll # 新设备轮询 tokenV1 暂时只支持邮箱密码 / 验证码 / Passkey 流程。
多账户
同一 access_token 仅绑定一个 user_id。多账户需要:
- 客户端管理多个 token(Hashee Mobile / Desktop 已实现”账户切换”)
- 服务端没有”机构账户” / “委托账户”概念(V1)
下一步
- REST 端点
- WebSocket 事件
- Webhook 协议
- 错误码 — 认证错误
- Agent 身份与密钥