跳转到内容

Layer 1 — 认证规则

查看 Markdown

认证规则控制应用允许使用哪些认证方式。系统会在向用户展示可选方式时(/reason/email)以及每次实际认证尝试中检查这些规则。

方式Payload说明
PASSKEY_USERNAMELESS{}WebAuthn / FIDO2 passkey 的 discoverable credential 流程。它控制邮箱输入前那个独立的「使用 passkey 登录」按钮。两种 passkey 方法用的是用户注册的同一个 passkey,只是入口不同。详见下文的 无用户名 passkey
PASSKEY_REASONED{}WebAuthn / FIDO2 passkey 的邮箱优先流程。它控制用户输入邮箱后出现的 passkey 选项。
EMAIL_VERIFICATION{}向用户邮箱发送一次性验证码。
STEAM_TICKET{ "allowedSteamAppIds": number[] }在 Steam 发行的游戏客户端内由 Steamworks SDK 发起的一次性 Steam ticket 交换,由 native-api POST /direct-issue/steam-ticket 消费。allowedSteamAppIds 把规则收紧到具体的 Steam App ID 列表。端到端用法见 原生客户端
STEAM_OPENID{}浏览器端的 “Sign in with Steam” 按钮,使用 Steam 的 OpenID 2.0 OP。此处解析得到的 Steam 身份与 STEAM_TICKET 共用同一条用户身份行,所以一个用户从游戏端首次登录后可以接着从网页按钮登录(反之亦然)。这条路径不需要 client ID、client secret、Web API key —— 通过 openid.mode=check_authentication 做无密钥验证。
ACCESS_KEY_DIRECT{}一次性的 AccessKey 凭据登录,由 native-api POST /direct-issue/access-key 消费。凭据格式与端到端流程见 原生客户端
GOOGLE_OAUTH{ "allowedHostedDomains": string[] }通过 Google 登录。allowedHostedDomains 为空时允许任意 Google 账户;填入 Google Workspace 域名(如 example.com)后,用户的 Google hd 声明必须命中其中一个。普通 Gmail 账户没有 hd,因此无法通过非空域名允许列表。
GITHUB_OAUTH{ "allowedGitHubOrgs": string[] }通过 GitHub 作为上游 OAuth 2.0 提供方登录(没有 id_token;profile 与已验证邮箱列表通过 GitHub REST API 拉取)。allowedGitHubOrgs 是 GitHub Organization login 的精确匹配列表(大小写不敏感);空数组表示不限制组织,非空表示用户必须属于其中至少一个组织。只有匹配规则包含非空允许列表时,才会请求 read:org scope。未配置组织限制时,授权页与 Phase 2 相同,只请求 read:user user:email
DISCORD_OAUTH{ "allowedDiscordGuilds": string[] }通过 Discord 登录。allowedDiscordGuilds 为空时允许任意 Discord 账户;填入 Discord 服务器 ID 后,用户必须属于至少一个服务器。启用服务器限制的应用会请求 guilds scope。只有当 Discord 同时返回非空 emailverified: true 时,邮箱才会被视为已验证;否则 Layer 2 EMAIL 规则会失败。
BATTLENET_OAUTH{}通过 Battle.net 登录。Battle.net 的 /userinfo 只返回 subject 和 BattleTag,没有邮箱,因此账户会被创建但不记录已验证邮箱;只有 EMAIL 身份准入规则的应用会拒绝这类账户。Battle.net 没有应用级限制,payload 为空。
X_OAUTH{}通过 X(原 Twitter)登录。X 的 v2 /2/users/me 不提供邮箱,因此与 Battle.net、Steam 一样,账户会被创建但不记录已验证邮箱;只有 EMAIL 身份准入规则的应用会拒绝这类账户。payload 为空。
ENTERPRISE_FEDERATION_APPLICATION_MANAGED{ "connectorAnchor": string }通过你自己组织注册为外部连接的 OIDC 或 SAML 身份提供方登录。connectorAnchor 指向该组织拥有的外部连接;一条规则显示一个按钮。详见使用你的 IdP 登录
ENTERPRISE_FEDERATION_DOMAIN_MANAGED{}允许应用接受强制 SSO 登录。payload 为空:外部连接会根据用户邮箱域名在登录时解析出来,不在规则里指定。没有这条规则的应用会拒绝被 SSO 管控的用户。详见使用你的 IdP 登录

STEAM_TICKETACCESS_KEY_DIRECT 的端到端用法见 原生客户端;两种企业联合方法见 域名与联合登录 一节。

每条认证规则描述一种认证方式。要允许多种方式,请分别创建多条规则。

{
"method": "PASSKEY_REASONED",
"payload": {},
"accessTokenTtlSeconds": null,
"refreshTokenTtlSeconds": null
}

STEAM_TICKETpayload 包含允许的 App ID 列表:

{
"method": "STEAM_TICKET",
"payload": { "allowedSteamAppIds": [480, 730] },
"accessTokenTtlSeconds": null,
"refreshTokenTtlSeconds": null
}

GOOGLE_OAUTH 可以用 allowedHostedDomains 限制 Google Workspace 域名:

{
"method": "GOOGLE_OAUTH",
"payload": { "allowedHostedDomains": ["example.com"] },
"accessTokenTtlSeconds": null,
"refreshTokenTtlSeconds": null
}

DISCORD_OAUTH 使用 Discord 服务器 ID,而不是服务器名称:

{
"method": "DISCORD_OAUTH",
"payload": { "allowedDiscordGuilds": ["974519864045756446"] },
"accessTokenTtlSeconds": null,
"refreshTokenTtlSeconds": null
}

两个 TTL 字段是可选的;如果提供,它们会参与发放令牌时的最小值计算

/establish 中的 authenticationConstraints 使用相同结构,用于限制单次认证请求:

{
"applicationAnchor": "my-app",
"authenticationConstraints": [
{ "method": "PASSKEY_REASONED", "payload": {} }
]
}
  • 字段缺失 → 不收紧;只看应用规则。
  • 字段存在且为空数组 → 拒绝。
  • 字段存在且非空 → 和应用规则做 AND。

某应用配置了两条认证规则:PASSKEY_REASONEDEMAIL_VERIFICATION。管理员入口在一次认证请求中传入 authenticationConstraints: [{ "method": "PASSKEY_REASONED", "payload": {} }]

方式应用允许?本次请求允许?结果
PASSKEY_REASONED提供
EMAIL_VERIFICATION隐藏

用户在这次会话里只看得到 passkey 选项,尽管应用本身也是允许邮箱方式的。

passkey 登录拆分成两个相互独立的 Layer-1 方法,而不是一条带 flag 的规则:

  • PASSKEY_REASONED邮箱优先流程:用户先输入邮箱,/reason/email 解析出其账户,然后用注册过的凭据完成挑战。
  • PASSKEY_USERNAMELESSdiscoverable credential 流程:在认证 UI 顶部、邮箱框之前,显示一个独立的「使用 passkey 登录」按钮。用户点一下,浏览器弹出原生 passkey 选择器,挑一个凭据并完成验证(指纹 / 面部 / PIN),整个过程无需输入邮箱。

「仅无用户名」的应用 —— 即没有任何邮箱框提供 passkey 选项 —— 只需仅允许 PASSKEY_USERNAMELESS 即可表达:

{
"method": "PASSKEY_USERNAMELESS",
"payload": {}
}

要点:

  • 这两个方法是独立的规则,payload 均为空。要邮箱优先入口就配 PASSKEY_REASONED,要独立按钮就配 PASSKEY_USERNAMELESS,两者都要就都配。已不再使用 allowUsernameless 这类开关。
  • 两个方法都解析到同一条共享的 PASSKEY 凭据行,因此通过其中一个流程注册的凭据可被另一个流程使用。
  • 每次 /establishauthenticationConstraints 可以携带 PASSKEY_USERNAMELESS,把本次登录收紧到只剩独立 passkey 按钮(与应用规则做 AND,和其它方法一样)。
  • Discoverable credential 流程要求 authenticator 设置 User Verified (UV) 标志(指纹 / PIN)。没有用户验证的无用户名登录会被拒绝,因为这里没有输入邮箱这一层确认。
  • 这两条规则不影响 passkey 的注册流程:用户仍然通过常规的”邮箱验证后注册 passkey”路径来添加凭据。PASSKEY_USERNAMELESS 只控制登录时是否提供这个独立按钮。