# 移动端会话安全规范

> Canonical path: `specs/identity/mobile-sessions.md`

## 范围

本规范定义通过工作区二维码登录 AgentTeam 移动端后的凭据归属、退出和远程撤销行为。移动端登录代表用户本人，能够在用户已有权限范围内查看工作区并操作智能体，因此必须是可识别、可撤销的账户级安全边界。

## 会话族

- 每次成功交换二维码配对码都会创建一个 `client_type=miniapp` 的会话族。
- 会话族保存稳定安装标识、用户可读设备名称、平台、创建时间、到期时间和撤销时间。
- access token 和 refresh token 都归属于一个会话族；refresh token 轮换产生的新 token 必须继承原会话族。
- 成功轮换 refresh token 时，会话族到期时间随新 refresh token 延长；已撤销或已过期的会话族不能通过刷新重新激活。
- 同一用户、同一安装标识再次配对时，服务端必须先撤销该安装此前仍有效的移动端会话族，避免客户端覆盖本地 token 后留下不可见凭据。
- 每个用户最多保留 20 个有效移动端会话族；新配对超过上限时，服务端撤销最早的有效会话族，使账户安全列表始终覆盖全部有效移动端登录。
- 安装标识只用于服务端识别同一应用安装，不作为公开设备指纹返回给客户端。

## 鉴权与撤销

- access token 鉴权除了检查 token 自身状态，还必须检查所属会话族未撤销且未过期。
- refresh token 轮换必须执行相同的会话族检查。
- 移动端主动退出必须调用服务端退出接口；服务端成功撤销后，客户端才能删除本地凭据。
- 账户所有者可以列出自己的全部有效移动端会话，并按会话族 ID 远程撤销其中任意一个。
- 远程撤销必须同时阻断该会话族已有的 access token 和 refresh token，包括刷新轮换后产生的 token。
- 移动端在刷新凭据时收到终态未授权响应，必须删除对应服务器的本地会话，使远程撤销在设备下次联网请求时收敛为退出状态。
- 用户只能列出和撤销自己的移动端会话。对不属于当前用户的会话族，撤销接口返回未找到，不能泄露其存在性。

## API 契约

- `GET /api/v1/me/mobile-sessions` 返回当前用户仍有效的移动端会话，按创建时间倒序排列。
- `DELETE /api/v1/me/mobile-sessions/:sessionFamilyId` 撤销当前用户拥有的指定移动端会话族。
- `POST /api/v1/auth/logout` 在当前 access session 属于会话族时撤销整个会话族；请求中提供的 refresh token 仍按既有契约一并撤销。
- `POST /api/v1/miniapp-pairing-exchanges` 要求移动端提交 `installationId`，并可提交 `deviceName` 与 `devicePlatform` 作为账户安全界面的展示信息。

## 数据访问约束

- 移动端会话列表必须按当前 `user_id` 和 `client_type` 查询，并受 20 个有效会话的产品上限约束；不得扫描其他用户的 token 或会话。
- 普通鉴权请求不得为了设备列表写入 `last_used_at` 等热路径状态。
- 撤销以会话族状态为唯一判断，不要求逐条更新其历史 token，从而避免 token 轮换次数放大撤销成本。
