跨 App SSO
授权码、PKCE、App session 和登出边界
跨 App SSO
用户先在 IWish Auth Portal 完成飞书或邮箱登录。访问已开通业务 App 时,Portal 为目标 OAuth Client 生成一次性授权码;业务 App 服务端使用 Client Secret 与 PKCE verifier 交换 opaque App Session。用户不需要在每个 App 再输入密码。
标准流程
- App 服务端生成
state、PKCE verifier 与 challenge,并把短期值放入 HttpOnly Cookie。 - 浏览器跳转
/v1/sso/authorize,参数包含 client、精确 redirect URI、state 与 challenge。 - Auth 验证用户、员工状态、组织、App、OAuth Client 和 callback。
- callback 获得一次性 code,服务端校验 state 后调用
/v1/sso/token。 - 服务端把返回的 opaque token 存入独立 HttpOnly App Cookie。
- 每个受保护请求通过
/v1/sso/session或 SDK 恢复 App Session 0.3。
授权码短时、一次性且绑定 Client、callback 与 PKCE challenge。Client Secret 只能在业务 App 服务端 Secret 管理中。不同 App 使用不同 OAuth Client 和 Cookie 名称,不能共享 session。
App Session 0.3
响应包含 sessionVersion="0.3"、authorizationDomain="application"、session、user、employee、clientAssignments、organization 和 app。app.authorizationMode 固定为 application_owned。响应不包含业务 roles、permissions 或 matchedRoles。
业务 App 使用 session.user.id 作为 iwish_auth_user_id 查找本地成员,再执行本地角色、permission 与业务数据范围检查。clientAssignments 只是客户项目与职责上下文,不是业务授权凭证。
内部与外部身份
内部员工通常为 identitySource=feishu,并返回员工、部门、岗位和在职状态。外部客户账号为 identitySource=email,employee=null,clientAssignments=[]。两类身份都必须经过当前 App 的本地成员与角色管理;不能因为邮箱属于客户域名就自动授权。
登出与撤权
单 App 登出撤销当前 App Session 并删除 Cookie;全局登出撤销用户所有 App Session。用户停用、飞书离职或冻结、组织停用、组织关闭 App、OAuth Client 停用等事件必须使新旧 session fail closed。本地角色撤销由业务 App 自己立即生效,不要求修改 Auth。
安全验收
必须测试 state/PKCE 错误、callback 不匹配、code 重放、跨 Client code、跨 App session、过期和撤销 session、伪造 Header、浏览器泄漏 Client Secret、无本地成员 403、外部账号无本地角色 403。业务 App 禁止直接接飞书、Supabase Auth 或 Auth 数据库。