- 生产应用使用
https://<name>.auth.didit.me, - 沙盒应用使用
https://<name>.sandbox.auth.didit.me, - 或者您的自定义域名(域名生效后)。
DIDIT_AUTH_ISSUER 设置为您的颁发者,末尾不要带斜杠;将 DIDIT_APPLICATION_ID 设置为您的应用 ID,token 会以 aud 字段携带该值。您的可发布密钥(publishable key)中编码了颁发者:在 pk_live_ 或 pk_test_ 之后的部分,就是经过无填充 base64url 编码的颁发者。
自定义域名生效后,它会取代默认主机成为颁发者。新 token 会在
iss 中写入该域名,发现文档会将 jwks_uri 指向该域名,您的可发布密钥也会随之变化。在刷新之前,使用默认主机签发的访问 token 调用 GET /session/ 会失败。激活域名时请更新 DIDIT_AUTH_ISSUER;或者在旧 token 于 5 分钟内过期之前,同时接受两个颁发者。发现与密钥
颁发者支持以下内容:
- 响应类型
code,响应模式query。 - 授权类型
authorization_code和refresh_token。 - PKCE 方法仅支持
S256。客户端为公开客户端:没有客户端密钥,client_id即您的应用 ID。 - 签名算法
ES256(P-256 密钥)。 - 作用域
openid、email、phone、profile和offline_access。
prompt=none。请使用 GET /session/ 读取并检查会话。
缓存与轮换
两份文档都返回Cache-Control: public, max-age=300,因此您和共享缓存可以将其保存 5 分钟。每个 IP 地址每分钟允许 1,200 次请求,每小时允许 12,000 次。这一限额远高于登录 endpoint 的速率限制,因为许多后端实例通常共用同一个地址。
- 每个密钥都有
kid;新密钥 ID 以k_开头。每个 token 都会在kid头部中注明其密钥。 - Didit 每 30 天轮换一次密钥。Didit 会在新密钥开始签名前一天发布该密钥,并在旧密钥停止签名后继续发布它一天。因此,缓存 5 分钟的 JWKS 在轮换期间仍可继续验证。
- 按
kid缓存密钥。当 token 包含您没有的kid时,重新获取 JWKS,但每分钟最多一次;如果仍找不到该密钥,则拒绝该 token。 - 当 Didit 吊销已泄露的密钥时,会立即将其从 JWKS 中移除,
GET /session/也会拒绝该密钥签发的所有 token。替换密钥会立即开始签名,无需提前一天发布。最多缓存 5 分钟的 JWKS 仍会接受已吊销的密钥,且尚不知道替换密钥,因此在缓存刷新之前,新 token 可能无法通过离线验证。
开始登录
打开托管页面,即authorization_endpoint:
快速入门会为您构建此请求。
交换授权码
回调会接收code 和 state。请校验 state,然后在 60 秒内交换授权码。每个授权码只能使用一次。请求体可以是 JSON,也可以是表单编码。
expires_in 表示访问 token 剩余的有效秒数。关闭多会话功能后,此次交换会结束该用户的其他会话。
访问令牌声明
访问令牌是一个 JWT,头部为alg: ES256 和 typ: at+jwt。其有效期最多为 5 分钟,且绝不会超过所属会话的有效期。
ID 令牌的头部为
typ: JWT。它包含与访问令牌相同的声明,但不含 client_id,另外还包含 auth_time 和 email_verified,以及在有值时的 email、name 和 phone_number。只有授权码交换得到的 ID 令牌才会包含 nonce(前提是登录时带有该值)。请在该令牌中校验它,因为刷新得到的 ID 令牌从不包含它。ID 令牌永远不会被当作访问令牌接受。
在服务器上验证令牌
在信任任何声明之前,请检查以下所有项目:alg为ES256,typ为at+jwt。拒绝所有其他算法,包括none。kid存在于您应用的 JWKS 中,且签名验证通过。iss等于您配置的签发者,aud等于您的应用 ID。exp和iat有效,允许最多 60 秒的时钟误差,且sub、sid和jti均存在。act为null。AI 智能体的访问令牌使用同一密钥签名,并带有相同的typ、iss和aud;只有act能将其区分出来。除非该端点接受智能体,否则请拒绝它;若接受,则只允许act.scopes授予的操作。GET /session/始终拒绝智能体的令牌。
GET /session/。
检查会话
sub、sid、application_id、vendor_data、amr、mfa_verified、email、email_verified、phone、verified_identity、verified、expires_at、post_logout_redirect_uri 和 organizations。每个组织条目包含 organization_id、organization__name、role 和 custom_role。
此检查比离线验证更严格。以下情况也会导致检查失败:会话被撤销、空闲超时或超过有效期;用户被封禁,或其邮箱不再通过验证;会话不再符合您的 MFA 策略(例如用户添加了身份验证器应用,或成为组织管理员之后);或令牌已被刷新替换。失败时返回 401 {"detail": "invalid_token"} 以及 WWW-Authenticate: Bearer。
GET /session/ 每个 IP 地址每分钟允许 30 次请求,每小时允许 300 次,该限制与 DELETE /session/ 共享。请在每次请求时离线验证令牌,并将此调用保留给确实需要的时刻。每次成功调用都会计为活动,因此会重新开始会话的 idle_timeout。
已验证的电子邮件并不等于身份验证。请为此读取 verified:没有时其值为 null,而令牌中则为 {}。
刷新令牌
- 刷新令牌是一个随机字符串,有效期至会话结束。
- 重复使用会结束会话。 当已使用过的刷新令牌再次出现时,Didit 会将其视为盗用的迹象:撤销该会话,并返回
400 {"error": "invalid_grant"}。该会话的令牌也会同时失效,包括之前那次刷新得到的令牌:使用其刷新令牌会失败,使用其访问令牌调用GET /session/会立即失败,不过在过期之前(最多 5 分钟内)仍可离线验证。 - 对于同一会话,请在标签页、设备和服务器实例之间一次只执行一次刷新,并将三个令牌一起替换。
- 如果刷新以
400失败或没有响应,请重新开始登录。不要盲目重试:如果刷新实际已成功,重试就构成重复使用。 503 {"error": "temporarily_unavailable"}表示刷新未发生,您的刷新令牌仍然有效。请使用退避策略重试。- Didit 会在刷新运行之前返回
429,因此请在Retry-After之后重试。令牌端点每个 IP 地址每分钟允许 30 次请求,每小时允许 300 次。此外,您应用的每个POST和DELETE请求共享机器人防护桶:这些端点合计每个 IP 地址每分钟 60 次请求,每台设备每分钟 30 次。在整个应用层面,刷新的桶容量为每分钟 6,000 次,其他所有POST和DELETE请求(包括浏览器和登录步骤)共用一个每分钟 3,000 次的桶,因此刷新不会耗尽您的登录额度。 - 若访问令牌的有效期为 5 分钟,每小时 300 次刷新大约可满足 25 名保持活跃的用户。如果您的服务器要为来自同一地址的大量用户刷新,请仅在请求需要新令牌时才刷新,并尽可能在浏览器或应用中刷新。
退出登录
使用用户当前的访问 token 调用DELETE /session/ 即可结束会话,并返回 204。该会话的刷新 token 随即失效,其访问 token 会立即无法通过 GET /session/ 验证;您离线验证的 token 则会保持有效,直到过期。之后,如果您设置了 post_logout_redirect_uri,请将用户跳转到该地址。
退出登录需要一个 GET /session/ 会接受的访问 token,即未过期、且未被刷新替换的 token。返回 401 表示会话并未结束。请先刷新,再使用新的访问 token 退出登录;如果刷新返回 400,则该会话已无法继续使用。
以下情况下,会话也会结束:
- 超过
session_lifetime(默认 30 天)或idle_timeout(默认 1 天), - 多会话功能关闭时,用户再次登录,
- 开启
revoke_on_password_change时,用户重置密码, - 您的团队在控制台中撤销该会话,或封禁该用户,
- 已使用过的刷新 token 被再次发送。
有效期
按用途存储凭据
- 验证 API 密钥和控制台 token 请保存在您的服务器上。
- 浏览器端的访问 token 应尽量保存在内存中。对于服务端渲染的应用,请使用安全的 HttpOnly Cookie,并防范依赖 Cookie 认证的请求遭受 CSRF 攻击。
- 移动端的刷新 token 请存储在平台提供保护的存储中。退出登录后,请清除本地状态。
- 切勿将 token 放入 URL 或日志中。