令牌与用户信息 开发人员
上次更新:2026年8月15日
令牌与用户信息
本文介绍如何在成功换取令牌后校验 ID Token、使用 Access Token,以及读取 UserInfo 返回的声明。
令牌类型
| 令牌 | 形态(门户应用) | 用途 |
|---|---|---|
id_token | JWT,ES256 签名 | 向客户端证明用户已认证;内含 pairwise sub 等 |
access_token | JWT,ES256 签名 | 调用 UserInfo 等受保护资源;可用 JWKS 验签 |
refresh_token | 不透明令牌(仅机密客户端) | 刷新 Access Token |
发现文档中的 id_token_signing_alg_values_supported 应包含 ES256。用于验签的公钥可从以下端点获取:
GET {ISSUER}/oauth2/jwks
建议缓存 JWKS,并根据 kid 选择密钥;发生密钥轮换时,请重新获取 JWKS。
ID Token 校验(必做)
至少校验:
- 签名:ES256 + JWKS。
iss:等于你的 Issuer(如https://api-passport.swaymoon.com)。aud:包含你的client_id。exp/iat:令牌未过期,并为时钟偏差保留合理的容差。nonce(若你在授权请求中发送了):与会话中保存的值一致。
ID Token 中的 sub 是面向你的应用(团队)的稳定用户标识。应用方应使用该字段作为关联本地用户的主键。
当前实现下,email 与多数资料类声明以 UserInfo 为准;请勿假设 ID Token 内一定含有 email 或 picture。例外:已授予 locale 时,ID Token 会包含 locale(BCP 47,如 zh-CN / zh-TW / en / ja),授权回调即可读取用户首选语言。校验完 ID Token 的 sub 后,用 Access Token 调用 UserInfo 读取其余声明。
Pairwise sub
通行账户对已绑定开发者团队的客户端使用 pairwise 主体标识:
- 同一自然人用户多次登录你的团队下的应用时,
sub保持相同。 - 同一用户向另一团队的应用授权时,
sub不同。 - 因此,不要假设可以通过
sub关联不同应用或团队中的用户,也不要使用邮箱替代sub作为唯一主键,因为用户可能更换绑定邮箱。
UserInfo
GET /userinfo
Host: api-passport.swaymoon.com
Authorization: Bearer ACCESS_TOKEN
该端点返回 JSON 格式的声明。其中,sub 与 ID Token 中的值一致(pairwise)。
始终包含
| 声明 | 含义 |
|---|---|
sub | pairwise 用户标识(只要有 openid) |
资料声明:分项授权 + 默认值
下列声明始终出现在 UserInfo 响应中(字段形状稳定)。是否为真实用户数据,取决于令牌 scope 是否包含对应细项(见《权限与同意》)。
| 声明 | 所需 scope | 已授权时 | 未授权时(默认值) |
|---|---|---|---|
name | name | 展示名 | 摇月用户 |
nickname | nickname | 昵称;未设置则为 摇月用户 | 摇月用户 |
picture | picture | 头像 HTTPS URL;未设置则为空字符串 | "" |
biography | biography | 个性签名;未设置则为空字符串 | "" |
gender | gender | male / female / other;未设置则为空字符串 | "" |
birthdate | birthdate | YYYY-MM-DD;未设置则为空字符串 | "" |
region | region | 地区代码;未设置则为空字符串 | "" |
preferred_username | preferred_username | 用户名;未设置则为空字符串 | "" |
locale | locale | BCP 47 标签(zh-CN / zh-TW / en / ja) | "" |
updated_at | 任一资料细项 | 资料更新时间(Unix 秒) | 0 |
不要把默认值当成用户真实资料。请结合令牌中的 scope 判断哪些字段已获授权;未出现在 scope 中的资料项仅为占位。
旧令牌若仍含整包 profile,服务端视为上述全部资料细项均已授权。
picture(头像)
已授予 picture 且用户已设置头像时,UserInfo 返回绝对 HTTPS URL(Issuer 域,例如 https://api-passport.swaymoon.com/media/avatars/…),可直接在浏览器或服务端拉取,无需额外鉴权。未设置头像时为空字符串。
接入方落库时可二选一(或按产品需要组合):
- 只存链接:把
pictureURL 写入本地用户资料,展示时直接引用通行账户提供的地址。无需自建对象存储或图床;实现简单。注意:用户日后更换头像后,旧 URL 可能失效(文件名含随机段),宜在登录/刷新资料时更新本地保存的链接,或展示前再读一次 UserInfo。 - 存头像文件:用你方服务端(或安全的客户端)GET 该 HTTPS URL,下载图片后写入自有存储,本地只保留你方资源地址。适合希望图片长期由己方 CDN 托管、或需离线/裁剪处理的场景。请遵守合理缓存与体积限制,勿高频重复拉取。
两种方式都依赖生产环境 Issuer 为 HTTPS;本地联调若 Issuer 为 http://…,返回的也可能是 HTTP,上线前请按生产配置验证。
email
仅当令牌包含 email 时返回:
| 声明 | 含义 |
|---|---|
email | 可用于联系该用户的邮箱地址(已验证) |
email_verified | true(在返回邮箱时) |
未授予 email 时,响应中不会包含上述邮箱声明(与资料默认值策略不同)。
用户在同意页可以选择用普通邮箱或隐私邮箱把邮箱权限授给你方:
| 用户选择 | 你方收到的 email | 真实邮箱 |
|---|---|---|
| 普通邮箱 | 用户账户绑定的邮箱 | 即该地址 |
| 隐私邮箱 | 专用于你方应用的中继地址(…@privaterelay.swaymoon.com) | 不会通过 UserInfo 或其它 OAuth 通道提供给你方;发往该中继地址的邮件会由通行账户转发至用户真实邮箱 |
两种情况下,email 都是可正常收信的地址,请按普通邮箱处理(注册建档、发信、展示即可)。请了解用户可能选择隐私邮箱,因此不要假设该地址一定是用户的私人常用邮箱,也不要尝试索取或推断真实地址。账号主键请仍使用 sub。
需要邮箱才能完成授权: 授权请求含 email,且用户勾选/必选授予该权限时,若账户尚未绑定邮箱,通行账户会先引导用户绑定并验证,成功后再继续同意与发码。因此令牌带有 email scope 时,UserInfo 应始终包含 email 与 email_verified。用户也可取消可选的 email 后继续(若你方未将其设为必选)。
撤销与内省
- 撤销:
POST {ISSUER}/oauth2/revoke(按照 RFC 7009 和服务器实现传入令牌)。 - 内省:
POST {ISSUER}/oauth2/introspect(机密客户端可查询令牌状态)。
具体参数以发现文档与服务器响应为准。
建档建议
- 用校验后的
sub查找或创建本地用户。 - 按令牌
scope解释资料字段;将未授权字段的默认值视为「不可用」,不要写入业务档案。 - 头像:优先决定「只存 HTTPS 链接」还是「下载后自建存储」,见上文
picture。 - 机密客户端须妥善保存
client_secret;非机密客户端无密钥。不要尝试收集或存储用户的通行账户密码。 - Access Token 的有效期较短,请按需刷新;用户退出登录时,可根据产品需要撤销 Refresh Token。
下一步:阅读《权限与同意》;如在接入过程中遇到问题,请参阅《示例与排错》。