Authagonal

Documentation

Everything you need to get started with Authagonal — from creating your first tenant to wiring SSO, SCIM, and custom branding.

快速入门

Authagonal 为每个租户提供完全符合标准的 OIDC 服务器。每个租户拥有自己的发行者 URL、发现文档和令牌端点——租户之间不共享基础设施。您可以在 5 分钟内从零开始完成登录流程的搭建。

创建租户

authagonal.io 注册并为您的租户选择一个 slug。该 slug 将成为您的发行者域名:{slug}.authagonal.io。创建账户后,验证您的电子邮箱以激活租户。

Authagonal signup page showing tenant slug input and email verification

在注册时为您的租户选择唯一的 slug

注册客户端

在门户侧边栏中导航到客户端,然后点击创建。为您的应用输入 clientIdclientName。然后配置至少一个重定向 URI——这是用户完成身份验证后跳转的地址。例如:https://app.example.com/callback

Client creation form with clientId, clientName, and redirect URI fields

在门户中注册新的 OAuth 客户端

本地开发

本地开发时使用 http://localhost:3000/callback 作为重定向 URI。Authagonal 允许 localhost 来源使用非 HTTPS 重定向 URI。

您的首次登录

最快的集成方式是使用 oidc-client-ts,一个轻量级的 JavaScript 和 TypeScript 应用 OIDC 客户端库。

oidc-client-ts integration
import { UserManager } from 'oidc-client-ts';

const mgr = new UserManager({
  authority: 'https://acme.authagonal.io',
  client_id: 'my-app',
  redirect_uri: 'https://app.example.com/callback',
  response_type: 'code',
  scope: 'openid profile email',
});

// Redirect to login
mgr.signinRedirect();

// On callback page
const user = await mgr.signinRedirectCallback();
console.log(user.profile); // { sub, email, name, ... }

如果您更喜欢不使用库的最简方式,可以使用标准的 OAuth 2.0 授权码流程配合原生 fetch

Minimal fetch-based flow
// 1. Redirect the user to the authorization endpoint
const authorizeUrl = new URL('https://acme.authagonal.io/connect/authorize');
authorizeUrl.searchParams.set('client_id', 'my-app');
authorizeUrl.searchParams.set('redirect_uri', 'https://app.example.com/callback');
authorizeUrl.searchParams.set('response_type', 'code');
authorizeUrl.searchParams.set('scope', 'openid profile email');
authorizeUrl.searchParams.set('code_challenge', codeChallenge);
authorizeUrl.searchParams.set('code_challenge_method', 'S256');
window.location.href = authorizeUrl.toString();

// 2. On the callback page, exchange the code for tokens
const res = await fetch('https://acme.authagonal.io/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: new URLSearchParams(window.location.search).get('code')!,
    redirect_uri: 'https://app.example.com/callback',
    client_id: 'my-app',
    code_verifier: codeVerifier,
  }),
});

const tokens = await res.json();
// tokens.id_token, tokens.access_token, tokens.refresh_token
Authagonal login page with email and password fields, branded with tenant logo

您的租户默认登录页面

沙箱模式

先在沙箱模式中测试您的集成。沙箱租户使用单独的 URL({slug}-sandbox.authagonal.io),可以随时从生产环境刷新而不影响正式用户。

仪表板

门户仪表板为您提供租户的实时概览。它展示最重要的指标——用户增长、身份验证活动,以及快速导航到门户中的每个功能。

概览

仪表板顶部显示欢迎消息和当前用户总数。下方的日活跃用户图表显示过去 7 天每天完成身份验证的唯一用户数,让您快速了解参与趋势。

Full dashboard view showing welcome banner, user count, and Daily Active Users line chart

仪表板主屏幕,包含 DAU 图表和活动概览

活动指标

活动指标面板显示四张统计卡片,汇总关键身份验证事件:

  • 成功登录——已完成的身份验证流程总数
  • 失败登录——凭证错误、账户锁定或策略拒绝
  • 活跃用户——所选时间段内完成身份验证的唯一用户数
  • SCIM 操作——来自已连接身份提供商的用户和组配置事件

使用时间范围筛选器在24 小时3 天7 天30 天之间切换。所有统计卡片和图表会更新以反映所选时间窗口。

Activity metrics panel with four stat cards and a time range filter bar showing 24h, 3d, 7d, and 30d options

可配置时间范围的活动指标

快速导航

指标面板下方,导航卡片直接链接到每个主要功能:客户端、用户、组、角色、SSO、SCIM、品牌和设置。每张卡片都显示简要说明,方便新团队成员快速了解。

客户端

OAuth 客户端代表通过您的租户进行用户身份验证的应用。每个客户端都有自己的重定向 URI、作用域、授权类型、令牌有效期和 MFA 策略配置。

客户端列表

客户端页面显示所有已注册客户端的表格。每行显示 clientId、显示名称、以彩色标签形式显示的允许授权类型,以及是否启用了 PKCE。点击任意行可打开完整的配置编辑器。

Clients table showing clientId, name, grant type badges, and PKCE status for each registered application

带有授权类型标签和 PKCE 指示器的客户端列表

创建客户端

点击创建客户端以注册新应用。您需要提供两个字段:

  • clientId——客户端的唯一标识符(例如 my-spa
  • clientName——易于阅读的显示名称
Create client form with clientId and clientName input fields

注册新的 OAuth 客户端

删除客户端

要删除客户端,请打开客户端配置,然后点击页面底部的删除客户端按钮。系统会要求您在永久删除前进行确认。已删除客户端的所有活跃会话和令牌将立即失效。

客户端配置参考

每个客户端都有一组全面的配置选项,分为多个部分。

常规设置

设置项描述默认值
clientName在同意屏幕和门户中显示的名称
requirePkce在授权码流程中要求 Proof Key for Code Exchange开启
requireClientSecret令牌请求时要求客户端密钥(对公共客户端如 SPA 禁用此项)关闭
allowOfflineAccess允许客户端通过 offline_access 作用域请求刷新令牌关闭
alwaysIncludeUserClaimsInIdToken将所有用户声明直接包含在 ID 令牌中,而非要求调用 UserInfo关闭
includeGroupsInTokens在 ID 令牌中以 groups 声明形式包含用户的组成员关系关闭

PKCE 安全性

禁用 PKCE 会降低授权码流程的安全性。仅对不支持 PKCE 的旧版客户端禁用此项。所有现代应用都应保持 PKCE 启用。

URI

URI 字段使用标签输入——输入值后按回车逗号添加。点击标签上的 X 可将其移除。

设置项描述
redirectUris身份验证后允许的回调 URL。必须与授权请求中的 redirect_uri 参数完全匹配。
postLogoutRedirectUris注销后允许重定向到的 URL。
allowedCorsOrigins允许对令牌和 UserInfo 端点进行跨域请求的源。
URI configuration section showing tag inputs for redirect URIs, post-logout URIs, and CORS origins

用于配置 URI 的标签输入字段

作用域与授权类型

设置项选项
allowedScopesopenid profile email offline_access
allowedGrantTypesauthorization_code client_credentials refresh_token device_code

令牌有效期

设置项描述默认值
accessTokenLifetimeSeconds访问令牌的有效时长1800(30 分钟)
identityTokenLifetimeSecondsID 令牌的有效时长300(5 分钟)
authorizationCodeLifetimeSeconds授权码可用于交换的有效时长300(5 分钟)
absoluteRefreshTokenLifetimeSeconds刷新令牌的最大有效期,不受活动状态影响2592000(30 天)
slidingRefreshTokenLifetimeSeconds刷新令牌在每次使用时重置过期时间,但不超过绝对有效期1296000(15 天)
Token lifetime configuration fields with numeric inputs for each lifetime setting

按客户端配置令牌有效期

登出 URI

客户端可以注册 back-channel 和 front-channel 登出 URI。两者均为可选——配置与您的应用清理会话方式相匹配的那一个或两个。

设置项描述
backChannelLogoutUri带签名登出令牌的服务器到服务器 POST。即使用户浏览器离线也可靠。
frontChannelLogoutUri在登出时加载到隐藏 iframe 中,使浏览器清理 cookie 和本地存储。
frontChannelLogoutSessionRequired启用时,登出 URL 会收到 isssid 查询参数,以便应用将登出与特定会话关联。

一起使用

Back-channel 保证服务器收到通知;front-channel 清理浏览器。大多数应用都会受益于同时配置两者。

MFA 策略

每个客户端可以使用按客户端设置覆盖租户范围的 MFA 策略。MFA 策略下拉菜单提供三个选项:

策略行为
已禁用此客户端不会提示 MFA
已启用用户可以选择注册 MFA;已注册的用户在登录时会收到提示
必需所有用户必须完成 MFA 才能通过此客户端进行身份验证
MFA policy dropdown showing Disabled, Enabled, and Required options on the client configuration page

按客户端的 MFA 策略覆盖

企业 SSO

企业 SSO 让您的客户使用自己的身份提供商。Authagonal 支持 SAML 2.0 和 OIDC 联合身份验证,配合基于域的路由,用户可以根据其电子邮箱地址自动跳转到正确的身份提供商。

SSO domain routing flow — shows how email domains are matched to SAML or OIDC identity providers

基于域的 SSO 路由

SAML 2.0 连接

要创建 SAML 连接,请导航到 SSO 页面并选择 SAML 选项卡。提供以下信息:

字段描述
connectionName此连接的可读名称(例如「Acme Corp Okta」)
entityId外部身份提供商的 SAML Entity ID
metadataUrl身份提供商的 SAML 元数据 XML 文档 URL

保存连接后,Authagonal 会获取元数据文档并导入身份提供商的签名证书、SSO 端点 URL 和名称标识符格式。元数据会定期刷新以获取证书轮换。

SAML connection creation form with fields for connection name, entity ID, and metadata URL

创建 SAML 2.0 SSO 连接

OIDC 连接

要创建 OIDC 联合身份验证连接,请选择 OIDC 选项卡并提供:

字段描述
connectionName此连接的可读名称
discoveryUrlOpenID Connect 发现 URL(例如 https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration)
clientId在外部身份提供商中为此联合注册的 client ID
clientSecret外部身份提供商注册的 client secret
OIDC connection creation form with fields for connection name, discovery URL, client ID, and client secret

创建 OIDC 联合身份验证连接

域路由

域路由根据用户的电子邮箱域名自动将用户重定向到正确的身份提供商。当用户在登录页面输入电子邮箱时,Authagonal 会检查域名部分(例如 acme.com)是否匹配任何已配置的 SSO 连接。如果匹配,用户将被无缝重定向到其组织的身份提供商。

电子邮箱域名SSO 提供商协议
acme.comAcme Corp OktaSAML 2.0
contoso.comContoso Azure ADOIDC
example.orgExample OneLoginSAML 2.0
Domain routing table showing email domains mapped to SSO connections with protocol type

域路由将电子邮箱域名映射到身份提供商

SP 发起的流程

SP 发起的流程是默认模式——用户从您的登录页面开始,自动路由到正确的身份提供商。用户也可以通过 /saml/{connectionId}/login/oidc/{connectionId}/login 直接链接到特定连接。

JIT 配置

默认情况下,当用户首次通过 SSO 登录且在您的租户中不存在时,Authagonal 会自动创建其账户(即时配置)。可以通过在创建或编辑连接时勾选禁用 JIT 配置来按连接禁用此功能。

禁用 JIT 配置后,只有预先配置的用户——通过 SCIM、门户的用户页面或 API——才能通过该连接登录。未知用户会收到 access_denied 错误,并被引导联系其管理员。

按连接设置

JIT 配置是按 SSO 连接控制的,而非租户范围。您可以让一个连接允许 JIT(例如,用于自行管理用户的合作伙伴组织),而另一个连接要求预先配置(例如,用于使用 SCIM 同步的企业客户)。

推广前测试

在向生产用户推广前,使用沙箱模式测试 SSO 连接。这可以让您在不影响正式身份验证流程的情况下验证身份提供商配置、属性映射和域路由。

用户

用户页面让您管理租户中的所有终端用户。您可以搜索用户、查看用户详情、创建新账户,并查看每个用户的配置来源。

搜索栏支持按电子邮箱或用户 ID 筛选。搜索有 300 毫秒的防抖延迟,因此在您输入时结果会更新,而不会过度调用 API。结果以每页 50 个用户分页——使用表格底部的导航控件在页面之间切换。

用户表格

用户表格为每个用户显示以下列:

描述
电子邮箱用户的电子邮箱地址,如果邮箱已确认则显示验证标识
用户 ID分配给用户的唯一标识符
全名名字和姓氏的组合
状态ActiveInactive ——表示账户是否已启用
MFAEnabledOff ——是否已注册多因素身份验证
来源SCIMLocal ——用户的创建方式
创建时间用户账户的创建日期
User list table with columns for email, user ID, name, status, MFA, source, and created date

带搜索栏和分页的用户列表

创建用户

点击创建用户以添加新的本地用户。表单需要填写:

字段描述
email用户的电子邮箱地址(在租户内必须唯一)
password初始密码(至少 8 个字符,必须符合您的租户密码策略)
firstName用户的名字
lastName用户的姓氏
Create user form with email, password, first name, and last name fields

创建新的本地用户

SCIM 配置的用户

通过 SCIM 创建的用户会带有「SCIM」标签,且不能通过门户更改密码。其生命周期——创建、更新和停用——完全由上游身份提供商管理。

用户详情

点击用户列表中的任意一行以打开其详情页。您可以在此编辑个人资料、管理角色、重置 MFA、查看自定义属性,以及删除用户。

个人资料

编辑用户的邮箱、姓/名、电话、公司、外部 ID 和激活状态。邮箱更改必须在租户内保持唯一;如果已被占用,API 会返回 email_in_use

角色

分配和取消在角色页面定义的角色。当客户端启用 includeRolesInTokens 时,角色成员关系会出现在 ID 和访问令牌中。

多因素认证

查看为用户注册的每个 MFA 凭据——身份验证器应用(TOTP)、WebAuthn/通行密钥以及恢复码——每个都有注册和最后使用时间戳。您可以删除单个凭据,或重置所有 MFA。重置会强制用户在下次登录时重新注册。

自定义属性

附加到用户的任意键/值数据。键必须唯一。属性通过用户资料 API 和 SCIM 公开,并可通过配置自定义 scope 的 userClaims 映射到访问令牌声明。

删除用户

永久删除该用户及其所有 MFA 凭据。输入用户邮箱以确认——无法撤销。

组让您组织用户并在令牌中包含组成员关系。组可以在门户中手动创建,也可以通过 SCIM 从外部身份提供商自动配置。

组列表

组页面显示租户中的所有组及以下信息:

描述
组名组的显示名称
成员当前组中的用户数量
来源SCIMManual ——组的创建方式
创建时间组的创建日期
Groups list table showing group name, member count, source badge, and created date

带来源指示器的组列表

创建组

点击创建组并输入组的 displayName。组名应具有描述性且在租户内唯一(例如「Engineering」、「Billing Admins」、「Beta Testers」)。

组详情与成员

点击任意组可打开详情视图。在这里您可以查看所有当前成员并管理成员关系:

  • 添加成员——输入用户 ID 将用户添加到组。
  • 移除成员——点击任意成员旁边的移除按钮即可单独移除。
Group detail view showing member list with user IDs and a field to add new members

在详情视图中管理组成员关系

令牌中的组

当客户端启用 includeGroupsInTokens 时,ID 令牌中会包含一个 groups 声明,其中包含用户的组成员关系。每个条目包含组的 idname

groups claim in ID token
{
  "sub": "user-123",
  "email": "jane@acme.com",
  "groups": [
    { "id": "grp-001", "name": "Engineering" },
    { "id": "grp-002", "name": "Beta Testers" }
  ]
}

按客户端启用

includeGroupsInTokens 设置在每个客户端上单独配置。导航到客户端的常规设置以启用它。

角色

角色支持应用中的基于角色的访问控制(RBAC)。在 Authagonal 中定义角色,将其分配给用户,并使用令牌中的 roles 声明在您的应用逻辑中执行授权。

管理角色

角色页面显示所有已定义角色的表格,支持内联编辑。每个角色包含:

描述
名称角色的唯一标识符(例如 "admin"、"editor"、"viewer")
描述角色所授予权限的可读描述
创建时间角色的创建日期

创建角色

点击创建角色并提供名称和描述。角色名称应简洁,并在应用中遵循一致的命名约定(例如,使用小写加连字符:billing-admin)。

内联编辑

角色支持直接在表格中内联编辑。点击任意角色上的铅笔图标进入编辑模式——名称和描述字段变为可编辑。修改值后,点击对勾图标保存。更改立即生效。

删除角色

点击任意角色上的删除图标将其移除。系统会要求您在永久删除前进行确认。移除角色不会追溯使现有令牌失效——该角色将不会出现在删除后签发的新令牌中。

Roles table with inline editing active, showing editable name and description fields with save and cancel icons

在角色表格中内联编辑角色

令牌中的角色

分配给用户的角色作为 roles 声明包含在 ID 令牌中。您的应用可以读取此声明来做出授权决策:

roles claim in ID token
{
  "sub": "user-123",
  "email": "jane@acme.com",
  "roles": ["admin", "billing-admin"]
}

SCIM 用户配置

SCIM 2.0(跨域身份管理系统)支持从 Okta、Azure AD、OneLogin 和 JumpCloud 等企业身份提供商自动配置用户和组。配置完成后,用户账户和组成员关系会自动从上游身份提供商同步到您的 Authagonal 租户。

SCIM provisioning flow — shows user lifecycle events flowing from enterprise IdP through Authagonal SCIM API to your app via TCC webhooks

SCIM 用户生命周期同步与下游配置

设置步骤

按照以下步骤为客户端启用 SCIM 用户配置:

  1. 选择客户端应用——选择 SCIM 配置将关联的 OAuth 客户端。
  2. 生成 SCIM 令牌——提供描述和到期天数,然后生成令牌。
  3. 立即复制令牌——原始令牌值仅显示一次。在关闭对话框前复制它。
  4. 配置您的身份提供商——在您的身份提供商的 SCIM 设置中,输入基础 URL 和 Bearer 令牌。
  5. 测试用户同步——从您的身份提供商触发测试同步,并验证用户是否出现在 Authagonal 门户中。

SCIM 基础 URL

使用以下基础 URL 配置您的身份提供商:

SCIM Base URL
https://{slug}.authagonal.io/scim/v2

{slug} 替换为您的租户 slug。

SCIM configuration page showing client selector, token generation form, and base URL

SCIM 设置页面,包含令牌生成功能

令牌管理

SCIM 令牌用于验证来自身份提供商的配置请求。您可以为每个客户端管理多个令牌:

字段描述
描述用于标识令牌的标签(例如「Okta Production SCIM」)
过期时间令牌有效期(天数,1 到 3650)。不需要频繁轮换的令牌可留空或设置较大的值。
状态活跃令牌正在使用中。已撤销的令牌显示 Revoked 标识且无法再用于验证请求。

要撤销令牌,请点击令牌旁边的撤销按钮。已撤销的令牌在列表中仍然可见(用于审计目的),但会立即停止接受请求。

SCIM token list showing active and revoked tokens with description, expiry date, and revoke button

令牌管理,包含活跃和已撤销令牌指示器

立即复制令牌

原始 SCIM 令牌在创建时仅显示一次。请立即复制——之后无法再次获取。如果您丢失了令牌,需要生成新令牌并更新您的身份提供商配置。

测试连接

通过查询 ServiceProviderConfig 端点验证您的 SCIM 集成是否正常工作:

Test SCIM connectivity
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://acme.authagonal.io/scim/v2/ServiceProviderConfig

成功的响应会返回一个 JSON 文档,描述支持的 SCIM 功能,包括批量操作、筛选和更改密码功能。

OAuth Scope

Scope 允许客户端请求用户数据或权限的特定部分。Authagonal 支持标准 OIDC scope 和您为自己的 API 定义的自定义 scope。

内置 Scope

Scope描述
openid任何 OpenID Connect 流程所必需。颁发 ID 令牌。
profile返回标准个人资料声明(name、given_name、family_name)。
email返回用户的电子邮件地址和验证状态。
offline_access与访问令牌一同颁发刷新令牌。

自定义 Scope

在 Scope 页面定义您自己的 scope。每个 scope 描述客户端可以请求的权限或资源(例如 billing.read、orders.write)。

字段描述
name在令牌请求中发送的 scope 标识符(例如 billing.read)。
displayName在同意屏幕上显示的可读标签。
description同意时显示名称下方的较长说明。
userClaims授予此 scope 时添加到访问令牌的额外声明。
showInDiscoveryDocument如果启用,scope 将出现在 /.well-known/openid-configuration 中。
emphasize在同意屏幕上将 scope 作为敏感项突出显示。
required防止用户在同意时取消选择该 scope。

同意集成

设置 RequireConsent: true 的客户端在首次请求时会提示用户。删除 scope 不会撤销已颁发的令牌——如有需要请显式撤销。

令牌上的自定义声明

自定义声明包含两半。来源是按用户的数据:每个 AuthUser 都有一个 customAttributes 字典,可以通过 Portal(用户 → 用户 → 自定义属性)、SCIM 或 TCC 配置钩子来填充。释放按 scope 进行:每个 scope 的 userClaims 列表声明允许离开服务器的键。

当客户端请求 scope 时,Authagonal 会遍历已授予的 scope,合并其 userClaims 列表,仅从用户的 customAttributes 中输出这些键。未知键会被静默丢弃 — 客户端无法通过猜测名称读取属性。标准 OIDC 声明 (subemailname 等) 遵循规范,不受 whitelist 限制。

Example: project-scope claims on an access token
# 1. On the user (Portal → Users → {user} → Custom Attributes)
department = "engineering"
employee_id = "E-1042"
seat_tier = "enterprise"

# 2. On a custom scope (Portal → Scopes → projects.read)
name        = "projects.read"
userClaims  = ["department", "seat_tier"]   # <-- whitelist

# 3. Client requests scope=openid projects.read
# Decoded access token (relevant fields only):
{
  "sub": "u-9b…",
  "scope": "openid projects.read",
  "department": "engineering",
  "seat_tier":  "enterprise"
  // employee_id is NOT emitted — it's not in the whitelist for any granted scope.
}

联合声明按会话覆盖

当用户通过上游 IdP(SAML/OIDC SSO)登录时,从 IdP 进入的会话级声明 — 例如从 SAML 断言映射出的 department 属性 — 流经同一 scope whitelist,但在键冲突时会战胜已持久化的 customAttributes。它们出现在该会话的令牌上(并在 refresh 轮换中存活),但不会回写到用户记录。

将 Scope 分配给客户端

客户端 → Scope 与授权选项卡中添加允许的 scope。客户端只能请求已被授予的 scope;未知的 scope 将被拒绝,返回 invalid_scope

品牌

自定义您的租户登录页面的外观和感觉。品牌设置让您将身份验证体验与产品的视觉形象相匹配——从 Logo 和颜色到高级 CSS 覆盖。

外观

设置项描述
appName显示在登录页面标题和浏览器标签上的应用名称
logoUrl您的 Logo 图片 URL。显示在登录页面顶部。推荐尺寸:200x60px 或类似宽高比。
primaryColor用于按钮、链接和焦点状态的主品牌颜色。通过颜色选择器或十六进制输入设置。更改值时实时预览会更新。
customCssUrl在默认样式之后加载的外部 CSS 文件 URL。用于高级样式覆盖。
Branding appearance settings with app name input, logo URL field, color picker with hex input, and custom CSS URL field

带实时颜色预览的外观设置

联系信息

设置项描述
supportEmail显示在登录页面上的支持电子邮箱地址。用户在需要帐户帮助时会看到此地址。

登录页面切换

控制租户登录页面上显示的元素:

开关描述默认值
showForgotPassword在登录表单上显示「忘记密码?」链接开启
showRegistration显示「注册」链接以支持自助用户注册开启
showPoweredBy在登录页面底部显示「Powered by Authagonal」标识开启
A customized login page showing a branded logo, custom primary color on the sign-in button, and support email in the footer

应用了自定义品牌的示例登录页面

自定义 CSS

如需完全控制登录页外观,请在品牌设置中提供 CSS 文件 URL。该文件会在默认样式之后加载,因此您的规则优先。

CSS 自定义属性

登录页面支持 CSS 自定义属性(变量)以便进行常见覆盖。在您的 CSS 文件中设置这些变量,即可修改颜色、字体和形状,无需编写复杂的选择器。
/* your-custom-styles.css */
:root {
--auth-bg: #1a1a2e;
--auth-card-bg: #16213e;
--auth-heading: #e0e0e0;
--auth-radius: 12px;
--auth-font: 'Inter', sans-serif;
}
变量描述默认
--auth-bg页面背景色#f3f4f6
--auth-card-bg登录卡片背景white
--auth-heading标题文字颜色#111827
--auth-radius卡片圆角半径0.5rem
--auth-font字体族inherit

深色模式

登录应用提供浅色、深色和跟随系统三种主题。用户在登录页面上通过切换按钮选择;选择会在会话间保留。当设置为 system 时,SPA 会实时跟踪 prefers-color-scheme

浅色值在 :root 中声明;深色覆盖仅限于 .dark。通过 customCssUrl 设置的租户品牌样式始终优先——无论用户选择何种主题,您的颜色都会保留。

元素选择器

如需更细粒度的控制,请使用 data-auth 属性定位特定元素。这些选择器在更新之间保持稳定 —— 在我们更改内部类名时不会失效。
选择器元素
[data-auth="page"]整页背景容器
[data-auth="header"]Logo 和应用名称区域
[data-auth="logo"]Logo 图像
[data-auth="app-name"]应用名称标题(未设置 Logo 时)
[data-auth="content"]主要内容区域(表单、消息)
[data-auth="login-form"]登录表单元素
[data-auth="email-field"]电子邮件输入包装器
[data-auth="password-field"]密码输入包装器
[data-auth="submit-button"]登录按钮
[data-auth="languages"]语言选择器栏

设置

配置租户范围的安全策略、Webhook 和环境设置。这些设置全局适用于所有客户端,除非在客户端级别被覆盖。

密码策略

定义租户中所有用户的密码复杂度要求:

设置项范围默认值
minPasswordLength6 – 1288
requireUppercase开 / 关开启
requireLowercase开 / 关开启
requireDigit开 / 关开启
requireSpecialChar开 / 关开启
Password policy settings showing minimum length slider and toggle switches for character requirements

密码策略配置

MFA 策略

租户范围的 MFA 策略设置默认的多因素身份验证行为。单个客户端可以覆盖此设置。

策略行为
DisabledMFA 不可用。用户无法注册 MFA。
EnabledMFA 为可选。用户可以选择注册,已注册的用户在登录时会收到提示。
RequiredMFA 为必需。所有用户必须注册 MFA 并在每次登录时完成第二因素验证。

会话与锁定

控制会话持续时间和账户锁定行为:

设置项范围默认值
sessionLifetimeMinutes5 – 43,200(30 天)60
maxFailedAttempts1 – 1005
lockoutDurationMinutes1 – 1,440(24 小时)10
Session and lockout settings with numeric inputs for session lifetime, max failed attempts, and lockout duration

会话和锁定配置

Webhook

Webhook 让你实时响应认证事件。两个事件 (onUserAuthenticatedonTokenIssued) 是可强制的 — 默认情况下它们异步触发,不会阻塞用户,但你可以按事件启用强制,使非 2xx 响应或 {"allow": false} 响应体拒绝该操作。其余事件都是通知 — 永远是触发即忘,从不阻塞。

事件类型描述
onUserAuthenticated可强制登录成功后触发。默认触发即忘,不影响登录延迟。开启 <code>webhookEnforceUserAuthenticated</code> 即可使其变为阻塞 — 非 2xx 响应或 <code>{"allow": false}</code> 响应体将拒绝登录。
onTokenIssued可强制在签发令牌之前触发 (authorization_code、refresh_token、client_credentials)。默认触发即忘。开启 <code>webhookEnforceTokenIssued</code> 即可使其变为阻塞 — 非 2xx 响应或 <code>{"allow": false}</code> 响应体将阻止令牌签发。
onUserCreated通知当新用户注册或通过 SCIM 配置时的即发即忘通知。
onUserUpdated通知当用户记录被更新(资料变更、角色变更、SCIM 更新)时的触发即忘通知。
onUserDeleted通知当用户被删除时的触发即忘通知(来自 Portal/SCIM,或由保留策略触发)。
onLoginFailed通知当登录尝试因凭证错误、锁定或策略拒绝而失败时的即发即忘通知。

其他 Webhook 设置:

设置项范围默认值描述
webhookTimeoutSeconds1 – 305等待强制执行 Webhook 响应的最大时间(超时前)
webhookFailOpen开 / 关开启启用后,如果强制执行 Webhook 不可达或超时,操作将被允许继续
Webhook configuration section showing URL inputs for each event type, timeout slider, and fail-open toggle

Webhook 事件配置

强制执行 Webhook 可用性

强制执行 Webhook 可以阻止身份验证流程。如果您的 Webhook 端点不可用且 webhookFailOpen 被禁用,则没有用户能够登录。除非您有严格的合规要求需要在 Webhook 失败时阻止,否则请使用失败开放模式。

验证 Webhook

一旦配置了任何 Webhook URL,Authagonal 就会为每个租户生成一个签名密钥(一个 whsec_… 值,在设置 → Webhook 下以只读方式显示)。每次出站投递都会带有一个 X-Authagonal-Signature: t=<unix>,v1=<hex> 头,其中 v1HMAC-SHA256(secret, "{t}.{body}"),基于原始请求体计算。在你的端点上重新计算它并进行常量时间比较,以确认请求确实来自 Authagonal 且未被篡改 —— 并拒绝 t 过于陈旧的投递以阻止重放攻击。

验证 Webhook (Node.js)
import crypto from 'node:crypto';

// rawBody MUST be the exact bytes Authagonal sent — verify before any JSON re-serialization.
function verifyAuthagonalWebhook(signatureHeader, rawBody, signingSecret) {
  const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
  const { t, v1 } = parts;

  // Replay protection: reject deliveries older than 5 minutes.
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;

  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(`${t}.${rawBody}`)
    .digest('hex');

  return v1.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}

轮换签名密钥

使用签名密钥旁的重新生成来轮换它 —— 例如在怀疑泄露之后。先前的密钥会立即失效,因此请用新值更新你的验证器,否则进行中的投递将开始无法通过签名校验。

维护窗口

为证书轮换和基础设施更新等破坏性操作设置首选维护窗口。选择一个 UTC 时间(0-23)——门户还会显示对应的本地时区时间以方便参考。

沙箱环境

沙箱环境是生产租户的完整克隆,可通过单独的 URL 访问。使用它来测试配置更改、SSO 集成和 Webhook 端点,而不影响正式用户。

操作描述
启用沙箱创建生产租户的沙箱副本。沙箱 URL 是您的租户 slug 加 -sandbox 后缀。
从正式环境刷新将沙箱环境与当前生产配置和用户数据同步。
禁用沙箱永久删除沙箱环境及其所有数据。

沙箱可通过 {slug}-sandbox.authagonal.io 访问。

Sandbox settings showing enable/disable toggle, refresh from live button, and sandbox URL display

沙箱环境控制

计费

通过门户的计费页面管理您的订阅和账单。此页面提供当前方案的概览,并提供访问 Stripe 计费门户以管理支付方式、发票和方案变更。

订阅信息

计费页面一目了然地显示您当前的订阅详情。您会看到一个状态标签,指示您的订阅状态——activetrialingpast_duecanceledunpaid——以及您的方案名称、当前计费周期(起止日期),以及您的订阅是否设置在当前周期结束时取消。

管理订阅

点击管理订阅按钮,在新窗口中打开 Stripe 计费门户。在那里您可以更新支付方式、查看和下载发票、更改方案或取消订阅。

如果尚未创建订阅,则会显示设置计费引导操作,指导您选择方案并输入支付信息。

Billing page showing subscription status, plan name, billing period, and Manage Subscription button

计费页面显示您当前的订阅详情并提供 Stripe 访问入口

支付安全

所有计费通过 Stripe 处理。您的支付信息绝不会存储在 Authagonal 服务器上。

自定义域名

通过您自己的域名(例如 auth.yourdomain.com)而非默认的 {slug}.authagonal.io 提供身份验证页面。自定义域名为您的用户提供无缝的品牌化身份验证体验。

添加域名

在添加域名表单中输入您要使用的主机名(例如 auth.yourdomain.com)。添加后,该域名将以 pending_verification 状态显示在您的域名列表中。

DNS 验证

创建一条 CNAME 记录,将您的域名指向 {slug}.authagonal.io。DNS 记录就位后,点击验证以检查 DNS 传播。

CNAME record
auth.yourdomain.com.  CNAME  acme.authagonal.io.

DNS 传播

DNS 传播最多可能需要 48 小时。如果验证失败,请等待后重试。

TLS 证书

域名验证通过后,您需要 TLS 证书以便用户可以通过 HTTPS 安全连接。Authagonal 支持两种选项:

自动(cert-manager)——Authagonal 使用 cert-manager 自动配置和续期 TLS 证书。这是大多数用户的推荐选项。无需额外配置。

自带证书(BYO)——以 PEM 格式上传您自己的证书和私钥。如果您的组织要求使用特定证书颁发机构的证书,此选项很有用。系统会跟踪证书到期时间,以便您在过期前续期。

域名状态

每个域名显示一个状态标签,指示其当前状态:pending_verification(DNS 尚未确认)、verified(DNS 已确认,TLS 待配置)、active(完全可用)或 failed(检测到配置问题)。

Domain list showing domains with status badges and verification controls

域名列表显示每个自定义域名及其当前状态

BYO certificate upload form with certificate and private key PEM fields

以 PEM 格式上传您自己的 TLS 证书和私钥

BYO 证书续期

请保持您的 BYO 证书已续期。过期的证书会导致用户的浏览器显示安全警告。

电子邮件配置

配置您的租户如何发送事务性电子邮件 —— 验证、密码重置和 MFA 通知。可在默认共享发件人、通过 Resend 验证的自定义域名,或自己的 SMTP 服务器之间进行选择。

电子邮件提供商

提供商描述设置
Default电子邮件通过我们共享的 Resend 基础设施从 noreply@authagonal.io 发送。无需配置 —— 开箱即用。
Resend Custom Domain通过 Resend 从您自己已验证的域名发送电子邮件。注册您的域名,添加 DNS 记录,验证所有权。
Custom SMTP通过您自己的 SMTP 服务器发送电子邮件。提供 SMTP 主机、端口、凭证和 TLS 设置。

发件人身份

发件人电子邮件和名称在所有提供商模式中共享。发件人电子邮件为必填;名称为空时将回退到租户名称。

字段描述
senderEmail发出电子邮件的 From 地址。在 Resend 自定义域名模式下必须位于已验证的域名下。
senderName收件人收件箱中显示的名称。

Resend 自定义域名

仅需在 Resend 验证一次您的发送域名,然后即可用作此租户的 From 地址。DNS TXT 记录(SPF、DKIM)由"域名"页面提供;Resend 会自动验证。

自定义 SMTP

使用您自己的 SMTP 服务器 —— 适用于内部中继、Resend 未覆盖的供应商或法规要求固定的场景。

字段描述
hostSMTP 服务器主机名(例如 smtp.example.com)。
port连接端口。STARTTLS 使用 587,隐式 TLS 使用 465,未认证的内部中继使用 25。
username认证用户名(可选 —— 未认证中继请留空)。
password认证密码。以加密方式存储在租户设置密钥中。
useTls要求 TLS。除非指向可信的内部中继,否则请保持启用。

自定义发送域名

使用 Resend 提供商时,您可以注册自己的域名,让电子邮件来自您的品牌(例如 noreply@acme.com),而不是 @authagonal.io。

  1. 进入"设置 → 电子邮件",选择 Resend 自定义域名提供商。
  2. 输入您的域名并点击"注册"。
  3. 将显示的 DNS 记录(DKIM、SPF 和 return path)添加到您域名的 DNS 中。
  4. 点击"检查验证"—— DNS 生效后(通常 1–10 分钟),域名状态将变为已验证。

DNS 传播

DNS 变更在全球传播最多可能需要 48 小时,但大多数提供商会在几分钟内更新。您可以根据需要多次检查验证状态。

测试

使用"设置 → 电子邮件"中的"发送测试邮件"按钮验证配置。系统将使用当前保存的设置向您的管理员邮箱发送测试邮件。

审计日志

审计日志提供对租户执行的所有管理操作的只读记录。通过门户或 API 进行的每项更改都会被记录完整的上下文,为合规和故障排除提供完整的追踪记录。

日志列

描述
时间戳操作发生的日期和时间
执行者执行操作的管理员的电子邮箱地址,自动操作显示为 "system"
操作执行的操作类型(例如 Client Created、Settings Updated)
实体操作目标,格式为 type:id(例如 client:my-app)
详情关于变更的附加上下文

跟踪的操作

以下管理操作会记录在审计日志中:

类别操作
客户端Client Created、Client Updated、Client Deleted
SSO 连接SAML Connection Created、SAML Connection Deleted、OIDC Connection Created、OIDC Connection Deleted
用户User Created、User Updated
设置Settings Updated、Branding Updated
域名Domain Added、Domain Verified、Domain Deleted
SCIMSCIM Token Created、SCIM Token Revoked
角色Role Created、Role Updated、Role Deleted
Group Created、Group Deleted
团队Team Member Invited、Team Member Removed
Audit log table showing timestamped administrative actions with actor, action, entity, and detail columns

审计日志提供所有管理操作的完整记录

保留

审计日志在租户的整个生命周期内保留,不可修改或删除。

备份

Authagonal 每小时自动备份您的租户数据。备份包括所有用户、组、角色、客户端、SSO 连接、SCIM 令牌、品牌信息和设置。您可以在"备份"页面查看备份历史并下载最新的完整备份。

Backups page showing backup history with timestamps, types, and entity counts

备份工作原理

  • 每日运行一次完整备份,捕获租户存储分片中的每个表。
  • 增量备份每小时运行一次,仅捕获自上次备份以来发生变化的行。
  • 备份存储在 Azure Blob Storage 中,使用与您的租户相同的托管标识。
  • 已删除的记录通过 tombstone 跟踪并包含在备份中,以确保审计的完整性。

下载备份

点击"下载最新"以获取 ZIP 文件,其中包含最新的完整备份以及随后合并的所有增量备份。每个表都导出为 JSONL 文件(每行一个 JSON 对象)。

备份格式

备份以 JSONL(JSON Lines)格式导出 —— 每个表每行一个实体。此格式易于解析、比较并导入到其他系统。

配置应用

配置应用在用户在您的租户中被创建或完成身份验证时接收实时 Webhook 通知。这使下游系统能够自动设置账户、分配许可证或同步用户数据,无需手动干预。

工作原理

当用户事件发生(创建或身份验证)时,Authagonal 使用 TCC(尝试/确认/取消)模式调用您的配置应用回调 URL。这种三阶段方式确保跨多个下游系统的可靠配置:

阶段端点用途
/tryPOST {callbackUrl}/try检查应用是否可以处理该用户。返回 200 表示接受,4xx 表示拒绝。
/confirmPOST {callbackUrl}/confirm在所有应用接受 /try 阶段后提交操作。
/cancelPOST {callbackUrl}/cancel如果在 /try 阶段另一个应用失败,则回滚操作。

Webhook 载荷

每个 Webhook 请求包含一个 JSON 载荷,包含以下字段:

字段类型描述
eventstring事件类型(例如 user.created、user.authenticated)
userIdstring用户的唯一标识符
emailstring用户的电子邮箱地址
namestring用户的显示名称
tenantIdstring您的租户标识符
timestampstring事件的 ISO 8601 时间戳

添加配置应用

要添加配置应用,请提供名称回调 URL 和可选的API 密钥。API 密钥作为 Bearer 令牌在每个 Webhook 请求的 Authorization 头中发送,允许您的应用验证来自 Authagonal 的请求。

测试

点击任意配置应用旁边的测试,向您的回调 URL 发送测试请求。测试结果显示 HTTP 状态码和响应正文,帮助您验证应用是否正确接收和处理 Webhook。

Provisioning apps page showing configured apps with test results displaying HTTP status and response body

测试配置应用以验证 Webhook 交付和响应处理

方案限制

每个租户的最大配置应用数量可配置,默认限制为 6 个。如果您的工作流程需要更多配置目标,管理员可以调整此限制。

API 密钥身份验证

如果设置了 API 密钥,它将作为 Bearer 令牌在 Authorization 头中发送。使用此密钥验证来自 Authagonal 的 Webhook 请求。

团队

团队页面管理门户管理员——可以通过管理门户访问和配置您的租户的人员。所有团队成员对租户配置的各个方面拥有完全管理权限。

管理员列表

管理员列表显示每位团队成员的姓名、电子邮箱和添加日期。当前用户行旁边会显示「您」标识,方便您识别自己的账户。

邀请管理员

要邀请新团队成员,请提供其电子邮箱姓名临时密码(至少 8 个字符)。受邀用户使用临时密码登录,应在首次登录时更改密码。

邀请字段

管理员邀请将创建一个完全配置的用户——无需邮件往返。

字段描述
email新管理员的邮箱地址。在租户中必须唯一。
name在管理员列表中显示的名称。
tempPassword受邀者首次登录时使用的临时密码。系统会要求他们更改。留空则自动生成并通过邮件发送。

移除管理员

点击任意团队成员旁边的移除以撤销其访问权限。移除确认前会显示确认对话框。您不能移除自己——团队中必须始终至少有一名管理员。

Team page showing the admin list with name, email, date added columns, a You indicator, and invite/remove controls

在团队页面管理门户管理员

无所有者角色

没有「所有者」角色的区分。所有门户管理员对租户配置拥有完全访问权限。请谨慎邀请人员。

导入与迁移

将现有的身份系统迁移到您的 Authagonal 租户。支持两种来源 —— Duende IdentityServer(一个 SQL Server 数据库)和 Auth0(Management API)。每种来源都会运行只读预览,让您在提交之前准确查看将要复制的内容。

从 Duende IdentityServer 导入

将现有的 Duende IdentityServer SQL Server 数据库中的 Clients、Scopes、用户和角色迁移到您的 Authagonal 租户。导入分为两个阶段 —— 预览和提交 —— 这样您可以在任何更改之前查看将要复制的内容。

导入的内容

导入器从 Duende 的 ConfigurationDb 和 ASP.NET Identity 表中读取数据,将映射的行写入您的租户。短时效资源(如 persisted grants、device codes 和签名密钥)会被跳过。

实体源表备注
ClientsClients、ClientSecrets、ClientGrantTypes、ClientScopes、ClientRedirectUris已禁用的 Client 将以禁用状态导入。已过期的 secret 会被跳过。
ScopesApiScopes、ApiResources、IdentityResources可识别的用户声明映射会被保留。
用户AspNetUsers、AspNetUserClaims密码哈希(ASP.NET Identity V3)原样复制,首次登录时重新哈希。
角色AspNetRoles、AspNetUserRoles角色分配会被保留。
外部登录AspNetUserLogins仅作参考保存;导入后请通过 SSO 重新连接上游 IdP。

提交前预览

粘贴您的 Duende ConfigurationDb / IdentityDb 连接字符串,然后点击 运行预览。预览会以只读方式连接并统计将要导入的每一行 —— 不会写入任何数据。

  • Clients、Scopes、用户、角色和角色分配的实体计数。
  • 所有者冲突 —— 其现有 <code>userId</code> 与传入的 Duende <code>sub</code> 不一致的租户管理员。
  • 对未知表和未映射列的警告,便于您了解哪些数据将被丢弃。
Import preview panel showing entity counts, owner collisions, and warnings before committing the import

带有计数、冲突和警告的预览面板

密码哈希

Duende 使用 ASP.NET Identity V3(PBKDF2)存储密码。Authagonal 的 PasswordHasher 可直接验证该格式,并在首次成功登录时重新哈希为原生格式 —— 用户无需重置流程即可保留现有密码。

所有者 UserId 轮换

如果租户管理员的邮箱在 Duende 数据库中存在,则该管理员的 Authagonal userId 会被轮换以匹配 Duende 的 sub。这样可以在切换后保持 token 和审计条目的一致性。预览会在提交前列出每一次冲突。

您可能会被登出

如果您自己的账号属于被轮换的管理员,导入完成后门户会立即将您登出,以便下次会话携带新的 userId。使用同一凭据重新登录即可。

执行导入

在查看预览后,点击 开始导入。提交阶段会将 Clients、Scopes、用户、角色和外部登录引用写入您的租户存储。重复的 clientIdscope nameemailrole name 会被跳过 —— 导入器可安全重复运行。

不会导入的内容

  • Persisted grants、device codes、server-side sessions —— 短时效,自动重新生成。
  • 签名密钥 —— Authagonal 为每个租户签发自己的密钥。
  • 自定义列和表 —— 任何超出 Duende 标准 schema 的内容都会以警告形式出现,以便您了解数据已被丢弃。
  • 已禁用的 Client —— 以禁用状态导入;准备好后可在 Clients 页面重新启用。

沙盒模式下不可用

导入仅对正式租户运行。导入前请退出沙盒模式。

从 Auth0 导入

将 Authagonal 连接到您的 Auth0 租户的 Management API,迁移您的应用、API、角色、用户和企业连接。导入的用户和应用 ID 会被保留,因此切换之后现有的 sub 和 client_id 引用仍可正常解析。

您需要准备的内容

在 Auth0 中创建一个授权访问 Management API 的机器到机器(Machine-to-Machine)应用,并授予以下读取 scope:read:usersread:clientsread:resource_serversread:rolesread:connectionsread:client_grants。将其域名、client ID 和 client secret 粘贴到导入表单中 —— 它们仅用于本次导入。

导入的内容

实体源表备注
应用clients、client-grants自动检测 public 与 confidential。client secrets 会被重新哈希,以便继续可用。
API 与 scopesresource-serversaudiences 和 scopes 会根据各 client 的 grants 分配给它们。
角色roles + 分配关系保留每个用户的角色分配关系。
用户users + identities档案和元数据会一并迁移;社交/企业身份将成为已关联的登录方式。
连接connections(OIDC)企业 OIDC 连接会成为联合提供方。SAML、社交和数据库连接会被跳过并给出警告。

密码

Auth0 的 Management API 从不返回密码哈希。如果您拥有 Auth0 支持团队协助导出的批量密码(NDJSON),请一并提供 —— bcrypt 哈希会原样导入,您的用户无需重置即可保留密码。该文件还包含您的完整用户集合,从而突破 Auth0 API 列表 1,000 个用户的上限。若不提供,用户将以档案形式导入,并在首次登录时设置新密码。

相同的预览、轮换与限制

上文所述的预览、owner-userId 轮换、可重复执行的提交以及沙盒限制,同样适用于 Auth0 导入。

API 参考

每个租户在 https://{slug}.authagonal.io 上暴露一个符合标准的 OIDC 服务器。所有端点遵循 OAuth 2.0 和 OpenID Connect 规范。此参考涵盖您的应用可能需要交互的每个端点。

OIDC Authorization Code Flow with PKCE — sequence diagram showing the 9-step flow between your app, the browser, and Authagonal

带 PKCE 的授权码流程

OIDC 发现和 JWKS

发现文档让 OIDC 客户端库可以自动配置自身。这两个端点均不需要身份验证。

GET /.well-known/openid-configuration

返回 OpenID Provider 配置文档。响应包含客户端与此租户交互所需的所有元数据。

字段描述
issuer租户发行者 URL
authorization_endpoint授权请求 URL
token_endpoint令牌交换 URL
userinfo_endpoint获取用户声明的 URL
jwks_uriJSON Web Key Set URL
revocation_endpoint令牌撤销 URL
introspection_endpoint令牌内省 URL
end_session_endpoint注销 / 结束会话 URL
device_authorization_endpoint设备授权请求 URL
pushed_authorization_request_endpoint推送授权请求端点的 URL (RFC 9126)。
require_pushed_authorization_requests租户是否在全局要求 PAR。即使此值为 <code>false</code>,单个客户端仍可以设置 <code>RequirePushedAuthorizationRequests = true</code>。
scopes_supported支持的作用域列表
response_types_supported支持的响应类型
grant_types_supported支持的授权类型
code_challenge_methods_supported支持的 PKCE 方法(S256)
backchannel_logout_supported是否支持后通道注销

GET /.well-known/openid-configuration/jwks

返回用于验证令牌签名的 JSON Web Key Set。响应包含一个 keys 数组,其中每个 RSA 公钥包含 ktyusekidalgne 字段。

Fetch discovery document
curl https://acme.authagonal.io/.well-known/openid-configuration

授权端点

GET /connect/authorize

发起授权码流程。用户必须有活跃会话,否则将被重定向到登录页面。成功后,用户将携带授权码被重定向回您的应用。

参数必需描述
response_type必须为 "code"
client_id您已注册的客户端标识符
redirect_uri必须与已注册的重定向 URI 完全匹配
scope以空格分隔的作用域列表(例如 "openid profile email")
state推荐用于 CSRF 防护的不透明值,在重定向中原样返回
code_challengePKCE 时必需code_verifier 的 SHA-256 哈希值经 Base64url 编码
code_challenge_methodPKCE 时必需必须为 "S256"
nonce可选绑定到 ID 令牌的值,用于防止重放攻击
login_hint可选预填充登录页面的电子邮箱字段

成功响应:302 重定向到 redirect_uri,附带 codestate 查询参数。

错误响应:302 重定向,附带 errorerror_descriptionstate 查询参数。

PKCE 必需

所有客户端默认要求 PKCE。生成一个 code_verifier(43 个或更多字符的随机字符串),使用 SHA-256 哈希,然后进行 Base64url 编码以创建 code_challenge

推送授权请求 (PAR)

RFC 9126。客户端不再把每个授权参数放在 URL 上,而是用普通的客户端认证将它们 POST 到 /connect/par,并取回一个短期的不透明 request_uri。浏览器随后访问 /connect/authorize?client_id=...&request_uri=... — 其它内容不会出现在浏览器历史、服务器日志或 Referer 头中,并且服务器已在客户端认证下完成参数完整性校验。

POST /connect/par

客户端认证与 /connect/token 相同:使用 HTTP Basic 携带 client_id/client_secret,或者通过表单字段提交凭据。公共客户端无需 secret 直接提交。请求体携带的参数与你通常发送给 /connect/authorize 的相同;request_uri 本身会被拒绝(规范 §2.1 禁止链式 PAR)。返回 201 Created

参数必需描述
client_id你的客户端 ID。必须与已认证的客户端一致。
client_secret机密客户端你的客户端密钥。机密客户端必填。
response_type必须为 "code"
redirect_uri必须与已注册的重定向 URI 完全匹配
scope以空格分隔的作用域列表(例如 "openid profile email")
code_challengePKCE 时必需code_verifier 的 SHA-256 哈希值经 Base64url 编码
code_challenge_methodPKCE 时必需必须为 "S256"
state推荐用于 CSRF 防护的不透明值,在重定向中原样返回
nonce可选绑定到 ID 令牌的值,用于防止重放攻击

响应

字段描述
request_uri一次性不透明引用,例如 <code>urn:ietf:params:oauth:request_uri:abc123…</code>。将其作为 <code>request_uri</code> 传给 <code>/connect/authorize</code>。
expires_in<code>request_uri</code> 的存活时间(秒)。默认为 90 — 与典型参考 IdP 一致。

在后续的 GET /connect/authorize?client_id=…&request_uri=… 调用中,所有其它参数都从已推送的载荷中读取,多余的查询参数会被忽略。授权调用上的 client_id 必须与推送请求时的客户端一致。一旦被消费(或 expires_in 到期),request_uri 会从存储中移除。

按客户端强制 PAR

在客户端上启用 要求 PAR(Portal → 客户端 → 客户端 → 高级),即可拒绝该客户端发起的普通 /connect/authorize 调用。对高风险客户端,推荐姿势是 RequirePushedAuthorizationRequests = true 与 PKCE 组合使用 — 这样就彻底消除了 URL 栏作为攻击面。
Push an authorization request and follow up
# 1. Push parameters (server returns request_uri + expires_in)
curl -X POST https://acme.authagonal.io/connect/par \
  -u "my-app:CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "response_type=code" \
  -d "redirect_uri=https://app.example.com/callback" \
  -d "scope=openid profile email" \
  -d "state=$(openssl rand -hex 16)" \
  -d "code_challenge=YOUR_CODE_CHALLENGE" \
  -d "code_challenge_method=S256"

# 2. Send the user to /authorize with only client_id + request_uri
# https://acme.authagonal.io/connect/authorize?client_id=my-app&request_uri=urn:ietf:params:oauth:request_uri:abc123...

令牌端点

POST /connect/token

用凭证交换令牌。请求必须使用 Content-Type: application/x-www-form-urlencoded。客户端身份验证可以通过 HTTP Basic auth(Authorization: Basic base64(client_id:client_secret))或表单正文参数(client_id + client_secret)提供。

授权码授权

参数必需描述
grant_type"authorization_code"
code来自重定向的授权码
redirect_uri必须与授权请求中使用的 URI 匹配
code_verifierPKCE 时必需用于生成 code_challenge 的原始随机字符串
client_id您的客户端标识符(如果未使用 Basic auth)
client_secret机密客户端您的客户端密钥(如果未使用 Basic auth)

刷新令牌授权

参数必需描述
grant_type"refresh_token"
refresh_token要交换的刷新令牌
client_id您的客户端标识符
client_secret机密客户端您的客户端密钥

客户端凭证授权

参数必需描述
grant_type"client_credentials"
client_id您的客户端标识符
client_secret您的客户端密钥
scope可选以空格分隔的请求作用域

设备代码授权

参数必需描述
grant_type"urn:ietf:params:oauth:grant-type:device_code"
device_code来自设备授权响应的设备代码
client_id您的客户端标识符
client_secret机密客户端您的客户端密钥

令牌响应:

字段描述
access_token用于 API 调用的访问令牌
token_type"Bearer"
expires_in令牌有效期(秒)
id_tokenOpenID Connect ID 令牌(请求 openid 作用域时)
refresh_token刷新令牌(授予 offline_access 作用域时)
Exchange authorization code with PKCE
curl -X POST https://acme.authagonal.io/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://app.example.com/callback" \
  -d "client_id=my-app" \
  -d "code_verifier=YOUR_CODE_VERIFIER"

UserInfo 端点

GET /connect/userinfo

返回已验证用户的声明。需要具有 openid 作用域的有效访问令牌。

字段类型描述
substring唯一用户标识符
emailstring用户电子邮箱地址
email_verifiedboolean电子邮箱是否已验证
given_namestring名字
family_namestring姓氏
namestring完整显示名称
phone_numberstring电话号码(如已提供)
org_idstring组织标识符
rolesstring[]已分配角色的数组
groupsobject[]组成员关系数组,每项包含 id 和 name
Fetch user info
curl https://acme.authagonal.io/connect/userinfo \
  -H "Authorization: Bearer ACCESS_TOKEN"

令牌内省(RFC 7662)

POST /connect/introspect

验证令牌并返回其元数据。需要客户端凭证(Basic auth 或表单正文参数)。

参数必需描述
token要内省的令牌
token_type_hint可选关于令牌类型的提示(例如 "refresh_token")

活跃令牌响应:

字段描述
activetrue
sub主体(用户 ID)
client_id令牌签发给的客户端
scope已授予的以空格分隔的作用域
iss发行者
exp过期时间(Unix 时间戳)
iat签发时间(Unix 时间戳)
aud受众
token_type令牌类型(例如 "Bearer")

非活跃令牌响应:{ "active": false }

始终返回 200 OK

根据 RFC 7662,内省端点始终返回 200 OK——从不返回 401 或 403。这可以防止令牌枚举攻击。无效或过期的令牌只会返回 active: false
Introspect a token
curl -X POST https://acme.authagonal.io/connect/introspect \
  -u "my-app:CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=ACCESS_OR_REFRESH_TOKEN"

令牌撤销(RFC 7009)

POST /connect/revocation

撤销先前签发的令牌。需要客户端凭证。

参数必需描述
token要撤销的令牌
token_type_hint可选关于令牌类型的提示(例如 "refresh_token")

根据 RFC 7009 规范,该端点始终返回 200 OK,即使令牌无效或已被撤销。

仅支持刷新令牌

目前支持刷新令牌撤销。访问令牌是无状态 JWT,无法被撤销——它们在自然过期前始终有效。

设备授权(RFC 8628)

POST /connect/deviceauthorization

为输入受限设备(CLI、智能电视、IoT 设备)发起设备授权流程。设备向用户显示一个代码,用户随后在另一台有浏览器的设备上批准请求。

参数必需描述
client_id您的客户端标识符
client_secret机密客户端您的客户端密钥
scope可选以空格分隔的作用域(默认为 "openid")

响应:

字段描述
device_code设备验证码(用于轮询)
user_code面向用户的代码,格式为 XXXX-XXXX
verification_uri用户访问以输入代码的 URL
verification_uri_complete预填充了 user_code 的 URL
expires_in600(秒——代码有效期为 10 分钟)
interval5(秒——最小轮询间隔)

批准流程:用户访问 verification_uri,输入 user_code,然后批准请求。同时,设备使用 device_code 轮询令牌端点。

轮询错误代码:

错误含义
authorization_pending用户尚未批准——继续轮询
expired_token设备代码已过期——重新开始流程
access_denied用户拒绝了授权请求
Request device authorization
curl -X POST https://acme.authagonal.io/connect/deviceauthorization \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=my-cli" \
  -d "scope=openid profile email"

结束会话 / 注销

GET POST /connect/endsession

注销当前用户会话,触发对所有注册了 BackChannelLogoutUri 的客户端的后通道注销,并撤销所有授权。

参数必需描述
id_token_hint可选ID 令牌——用于验证 post_logout_redirect_uri
post_logout_redirect_uri可选注销后重定向的目标地址(必须已注册)
state可选在重定向中返回的不透明值

如果提供了有效的 post_logout_redirect_uri 且匹配已注册的 URI,用户将收到 302 重定向。否则,将返回 JSON 响应确认会话已结束。

后通道注销

当用户注销时,Authagonal 向每个客户端的 BackChannelLogoutUri 发送签名 JWT。JWT 包含 subaudisshttp://schemas.openid.net/event/backchannel-logout 事件声明。您的应用应在收到此通知时使用户的本地会话失效。

SCIM 2.0 API 参考

Authagonal 支持 SCIM 2.0 协议,用于自动化用户和组的配置。Okta、Azure AD 和 OneLogin 等身份提供商可以使用此 API 将您的 Authagonal 租户与企业目录保持同步。

基础 URL:https://{slug}.authagonal.io/scim/v2

身份验证:所有请求需要 Bearer 令牌。在门户的设置 > SCIM 用户配置中生成 SCIM 令牌。

通用请求头:

请求头
AuthorizationBearer SCIM_TOKEN
Content-Typeapplication/scim+json

列表端点通过 startIndex(从 1 开始)和 count(最大 200)查询参数支持分页,并通过 filter 参数支持筛选(例如 userName eq "user@example.com")。

用户

GET /scim/v2/Users — 列出用户,支持可选的分页和筛选。

查询参数描述
startIndex第一个结果的从 1 开始的索引(默认:1)
count每页最大结果数(最大:200)
filterSCIM 筛选表达式(例如 userName eq "user@example.com")

GET /scim/v2/Users/{id} — 通过 Authagonal 用户 ID 获取单个用户。

POST /scim/v2/Users — 创建新用户。返回 201 Created。

字段必需描述
userName电子邮箱地址(在租户内必须唯一)
name.givenName名字
name.familyName姓氏
displayName完整显示名称
active用户是否处于活跃状态(默认:true)
externalId来自上游身份提供商的标识符

PUT /scim/v2/Users/{id} — 完全替换用户资源。必须提供所有字段。

PATCH /scim/v2/Users/{id} — 使用 SCIM PatchOp 进行部分更新。

操作支持的路径示例值
replaceactive, name.givenName, name.familyName, externalIdtrue / false,或字符串值
addname.givenName, name.familyName, externalId一个字符串值
removeexternalId(无需值)

DELETE /scim/v2/Users/{id} — 软删除用户(停用账户并撤销所有令牌)。返回 204 No Content。

Create a user via SCIM
curl -X POST https://acme.authagonal.io/scim/v2/Users \
  -H "Authorization: Bearer SCIM_TOKEN" \
  -H "Content-Type: application/scim+json" \
  -d '{
    "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
    "userName": "jane@acme.com",
    "name": {
      "givenName": "Jane",
      "familyName": "Smith"
    },
    "displayName": "Jane Smith",
    "active": true,
    "externalId": "ext-12345"
  }'

GET /scim/v2/Groups — 列出所有组,支持可选的分页和筛选。

GET /scim/v2/Groups/{id} — 通过 ID 获取单个组,包括其成员列表。

POST /scim/v2/Groups — 创建新组。返回 201 Created。

字段必需描述
displayName组显示名称
members成员对象数组,每个对象包含一个 value 字段(用户 ID)
externalId来自上游身份提供商的标识符

PUT /scim/v2/Groups/{id} — 完全替换组资源(包括其成员列表)。

PATCH /scim/v2/Groups/{id} — 用于添加或移除组成员的部分更新。

DELETE /scim/v2/Groups/{id} — 硬删除组。返回 204 No Content。

Add members to a group via PATCH
curl -X PATCH https://acme.authagonal.io/scim/v2/Groups/GROUP_ID \
  -H "Authorization: Bearer SCIM_TOKEN" \
  -H "Content-Type: application/scim+json" \
  -d '{
    "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
    "Operations": [
      {
        "op": "add",
        "path": "members",
        "value": [
          { "value": "USER_ID_1" },
          { "value": "USER_ID_2" }
        ]
      }
    ]
  }'

SCIM 错误响应

当 SCIM 请求失败时,响应正文遵循 SCIM 错误模式:{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "400", "detail": "..." }。常见状态码包括 400(错误请求)、404(资源未找到)、409(冲突 / 重复)和 429(频率限制)。

Portal API(自动化)

Portal API 让您自己的后端能够自动化您在门户中所能执行的一切操作——管理用户、客户端、组、角色、作用域、SSO 连接和设置——通过一种机器对机器(M2M)凭据完成。它与门户 UI 调用的是同一套 API。

基础 URL:https://portal-api.<your-domain>/api/v1。请求通过 Bearer 访问令牌进行身份验证;租户取自令牌,而非 URL。

创建 API 凭据

在门户中,打开 Clients → Create API credential,选择一个访问级别并为其命名。Authagonal 会生成一个为 Portal API 配置好的 OAuth client_credentials 客户端,并返回 Client ID 和密钥。

立即复制密钥

客户端密钥仅显示一次,就在创建之后。请在关闭对话框前将其保存到您的密钥管理器中——如果丢失,请删除该凭据并重新创建一个。

访问级别

Scope授予权限
tenant:owner完全访问,包括破坏性的、仅限所有者的操作,例如删除整个租户。
tenant:admin管理除仅限所有者操作之外的一切——用户、客户端、SSO、组、角色、品牌和设置。
tenant:developer管理客户端、作用域和配置应用。
tenant:support为支持任务读取和管理用户。

您只能授予自己拥有的权限

凭据的权限不能高于创建它的人。管理员无法签发所有者级别的凭据,且平台管理作用域永远无法授予凭据。

获取令牌

在您的管理租户令牌端点——https://<your-tenant>.<your-domain>/connect/token——用该凭据换取访问令牌,然后将令牌作为 Bearer 请求头发送给 Portal API。令牌有效期为一小时。

获取令牌,然后调用 API
# 1. Exchange the credential for an access token (your tenant's token endpoint)
curl -X POST https://acme.authagonal.io/connect/token \
  -d grant_type=client_credentials \
  -d client_id=api-3f2a... \
  -d client_secret=YOUR_CLIENT_SECRET \
  -d scope=tenant:admin

# Response: { "access_token": "ey...", "token_type": "Bearer", "expires_in": 3600 }

# 2. Call the Portal API with the access token
curl https://portal-api.authagonal.io/api/v1/users \
  -H "Authorization: Bearer $ACCESS_TOKEN"

端点

所有路径均相对于基础 URL,并需要 Bearer 访问令牌。每个分组旁的作用域是该凭据所需的最低访问级别。列表端点接受 startIndex 和 count 查询参数。

客户端tenant:developer

GET/api/v1/clients— 列出 OAuth 客户端。

GET/api/v1/clients/{id}— 按 ID 获取单个客户端。

POST/api/v1/clients— 创建客户端。返回客户端 ID;对于机密客户端,还会返回一次性密钥。

PUT/api/v1/clients/{id}— 更新客户端(重定向 URI、授权类型、令牌有效期、PKCE/PAR 要求)。

DELETE/api/v1/clients/{id}— 删除客户端。

POST/api/v1/clients/api-credential— 创建机器对机器的 Portal API 凭据。

用户tenant:support

GET/api/v1/users— 列出用户。支持 startIndex、count 和 search(邮箱/姓名前缀)。

GET/api/v1/users/count— 租户的用户总数。

GET/api/v1/users/stats/mfa— MFA 注册统计。

GET/api/v1/users/{id}— 获取单个用户。

POST/api/v1/users— 使用邮箱和密码创建用户。

PUT/api/v1/users/{id}— 更新用户(资料、邮箱、启用/封禁状态)。

DELETE/api/v1/users/{id}— 删除用户。

GET/api/v1/users/{id}/mfa— Get a user's enrolled MFA methods.

DELETE/api/v1/users/{id}/mfa— Reset a user's MFA enrollment.

角色tenant:admin

GET/api/v1/roles— 列出角色。

POST/api/v1/roles— 创建角色。

DELETE/api/v1/roles/{id}— 删除角色。

POST/api/v1/roles/assign— 为用户分配角色。

POST/api/v1/roles/unassign— 移除用户的角色。

tenant:admin

GET/api/v1/groups— 列出组。

GET/api/v1/groups/{id}— 获取组及其成员。

POST/api/v1/groups— 创建组。

POST/api/v1/groups/{id}/members— 向组中添加成员。

DELETE/api/v1/groups/{groupId}/members/{userId}— 从组中移除成员。

DELETE/api/v1/groups/{id}— 删除组。

GET/api/v1/group-role-mappings— 列出组到角色的映射(根据组成员身份在签发令牌时授予的角色)。

作用域tenant:developer

GET/api/v1/scopes— 列出 API 作用域。

POST/api/v1/scopes— 创建作用域。

DELETE/api/v1/scopes/{name}— 删除作用域。

SSO 连接tenant:admin

GET/api/v1/saml/connections— 列出 SAML 连接。

POST/api/v1/saml/connections— 创建 SAML 连接。

DELETE/api/v1/saml/connections/{id}— 删除 SAML 连接。

GET/api/v1/oidc/connections— 列出 OIDC 连接。

POST/api/v1/oidc/connections— 创建 OIDC 连接。

DELETE/api/v1/oidc/connections/{id}— 删除 OIDC 连接。

GET/api/v1/sso/domains— 列出路由到 SSO 连接的域名(home-realm 发现)。

品牌tenant:admin

GET/api/v1/branding— 获取租户品牌设置(颜色、logo、支持的语言)。

PUT/api/v1/branding— 更新租户品牌设置。

设置tenant:admin

GET/api/v1/settings— 获取租户设置(webhook、公开注册、令牌策略)。

PUT/api/v1/settings— 更新租户设置。

POST/api/v1/settings/webhook-secret/regenerate— 轮换 webhook 签名密钥。

POST/api/v1/settings/test-email— 使用当前邮件配置发送测试邮件。

自定义域名和邮件tenant:admin

GET/api/v1/custom-domains— 列出自定义登录域名及其验证状态。

POST/api/v1/custom-domains— 添加自定义域名。

POST/api/v1/custom-domains/{domain}/verify— 为自定义域名触发 DNS 验证。

DELETE/api/v1/custom-domains/{domain}— 移除自定义域名。

GET/api/v1/email/domains— 列出发件人邮件域名。

审计日志tenant:admin

GET/api/v1/audit— 查询租户审计日志。

通过 SCIM 预配用户

如需从 IdP(Entra、Okta)批量预配用户和组,请使用 SCIM 2.0 API,而不是这些端点。

示例:创建用户

POST /api/v1/users
curl -X POST https://portal-api.authagonal.io/api/v1/users \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada@acme.com",
    "password": "S3cure-temp-passw0rd",
    "firstName": "Ada",
    "lastName": "Lovelace"
  }'

# 200 OK
# { "userId": "8f3a...", "email": "ada@acme.com" }

UI 能做的一切

Portal API 公开了门户 UI 所使用的同一套端点,因此您在门户中能执行的任何操作都可以自动化——但受凭据访问级别的限制。

身份验证流程

身份验证流程涵盖终端用户如何与您的 Authagonal 租户交互——登录、注册、重置密码和设置 MFA。这些端点由托管登录页面使用,如果您正在构建自定义登录 UI,也可以直接调用。

登录

POST /api/auth/login

使用电子邮箱和密码验证用户身份。成功后,签发会话 Cookie 并返回用户配置文件。如果配置了 MFA,响应会指示在会话完全建立之前需要第二因素。

请求正文:

Login request
{
  "email": "user@example.com",
  "password": "correct-horse-battery-staple"
}

成功响应:

字段类型描述
userIdstring唯一用户标识符
emailstring用户电子邮箱地址
namestring完整显示名称
mfaAvailableboolean用户是否已注册 MFA 方法

MFA 必需响应:当用户已注册 MFA 时,响应包含 mfaRequired: true 以及 challengeId 和列出可用 MFA 方法的 methods 数组。

MFA 设置必需响应:当租户要求 MFA 但用户尚未注册时,响应包含 mfaSetupRequired: true 和用于注册流程的 setupToken

错误响应:

错误代码HTTP 状态描述
invalid_credentials401电子邮箱或密码不正确
account_disabled403账户已被管理员停用
email_not_confirmed403用户尚未验证其电子邮箱地址
locked_out423账户已被临时锁定(包含 retryAfter 秒数)
sso_required409电子邮箱域名已配置 SSO(包含 redirectUrl)

SSO 检查:如果用户的电子邮箱域名配置了 SSO 连接,登录端点将返回 sso_requiredredirectUrl。客户端应将用户重定向到 SSO 提供商。

账户锁定:连续 maxFailedAttempts 次登录失败后,账户将被锁定 lockoutDurationMinutes。这两个值均可在租户设置中配置。

托管登录页面

登录端点通常由托管登录页面调用,而非直接由您的应用调用。使用 OIDC 授权码流程发起身份验证——您的用户将自动被重定向到托管登录页面。

注册

POST /api/auth/register

创建新用户账户。验证邮件会自动发送——用户必须在登录前验证其电子邮箱。

请求正文:

Registration request
{
  "email": "newuser@example.com",
  "password": "a-strong-password-here",
  "firstName": "Jane",
  "lastName": "Smith"
}
字段必需描述
email电子邮箱地址(必须唯一)
password必须符合租户密码策略
firstName名字
lastName姓氏

成功:201 Created,返回新账户的 userId

错误响应:

错误代码HTTP 状态描述
email_already_registered409该电子邮箱已存在关联账户
weak_password400密码不符合租户密码策略
rate_limited429注册尝试次数过多
provisioning_rejected422配置 Webhook 拒绝了该注册

密码策略

在提交前通过 GET /api/auth/password-policy 检查租户的密码要求。返回最小长度、所需字符类别以及是否启用了泄露密码检查。

密码重置

POST /api/auth/forgot-password

请求密码重置邮件。无论电子邮箱是否存在,端点始终返回成功响应,以防止电子邮箱枚举。

Forgot password request
{
  "email": "user@example.com"
}

POST /api/auth/reset-password

使用邮件链接中的令牌重置用户密码。

Reset password request
{
  "token": "RESET_TOKEN_FROM_EMAIL",
  "newPassword": "new-strong-password"
}

成功密码重置的副作用:

  • 失败登录尝试计数器重置为零
  • 所有现有刷新令牌被撤销
  • 生成新的安全戳(使所有现有会话失效)

MFA 设置与验证

Authagonal 支持三种 MFA 方法:TOTP(身份验证器应用)、WebAuthn(安全密钥和生物识别)和一次性恢复代码。

TOTP 设置

POST /api/auth/mfa/totp/setup — 返回 QR 码数据 URI 和手动输入密钥。用户使用身份验证器应用(Google Authenticator、Authy、1Password 等)扫描 QR 码,然后确认注册。

POST /api/auth/mfa/totp/confirm — 通过验证身份验证器应用中的 6 位数代码来确认 TOTP 注册。

Confirm TOTP enrollment
{
  "code": "123456"
}

WebAuthn 设置

POST /api/auth/mfa/webauthn/setup——返回 WebAuthn API 的凭证创建选项。浏览器使用这些选项调用 navigator.credentials.create()

POST /api/auth/mfa/webauthn/confirm — 通过提交浏览器的证明响应来确认 WebAuthn 注册。

恢复代码

POST /api/auth/mfa/recovery/generate — 生成 10 个一次性 8 字符恢复代码。每个代码只能使用一次以绕过 MFA。

恢复代码仅显示一次

恢复代码仅在生成时显示,之后无法再次获取。如果用户同时丢失了身份验证器设备和恢复代码,管理员必须在门户中手动删除其 MFA 凭证后用户才能再次登录。

MFA 验证

POST /api/auth/mfa/verify — 在成功密码登录后完成 MFA 挑战。

字段必需描述
challengeId来自登录响应的挑战 ID
method"totp"、"recovery" 或 "webauthn"
codeTOTP / 恢复代码6 位 TOTP 代码或 8 字符恢复代码
assertionWebAuthn来自 navigator.credentials.get() 的断言响应

MFA 状态

GET /api/auth/mfa/status — 返回用户当前已注册的 MFA 方法。

SSO 登录流程

Authagonal 支持 SAML 2.0 和基于 OIDC 的 SSO 连接。基于域的路由根据用户的电子邮箱地址自动检测使用哪个 SSO 提供商。

SSO 检查

GET /api/auth/sso-check?email=user@acme.com

字段类型描述
ssoRequiredboolean该电子邮箱域名是否需要 SSO
providerTypestring"saml" 或 "oidc"
connectionIdstringSSO 连接标识符
redirectUrlstring将用户重定向到 SSO 登录的 URL

SAML 流程

用户被重定向到 GET /saml/{connectionId}/login,该端点向身份提供商发送 SAML AuthnRequest。身份提供商验证用户身份后将 SAML 响应发回 Assertion Consumer Service (ACS) 端点。Authagonal 验证断言、创建或更新用户并签发会话 Cookie。

用于配置身份提供商的 SAML 元数据可在 GET /saml/{connectionId}/metadata 获取。

OIDC 流程

用户被重定向到 GET /oidc/{connectionId}/login,该端点使用 PKCE 重定向到上游身份提供商。用户完成身份验证后,回调端点 /oidc/callback 交换授权码、验证 ID 令牌并创建或更新用户。

JIT 配置:SAML 和 OIDC 流程均支持即时配置。如果用户在租户中不存在,将根据身份提供商的声明自动创建。如果用户已存在,其配置文件属性将更新为与提供商的最新值匹配。

基于域的路由

基于域的路由意味着您的用户无需知道他们使用的是哪个 SSO 提供商。只需输入电子邮箱地址即可——Authagonal 会将域名匹配到正确的 SSO 连接并自动重定向。

构建自定义登录界面

用您自己的界面替换 Authagonal 托管的登录、注册、密码重置和 MFA 界面,同时让 Authagonal 继续处理身份验证、MFA、SSO、会话和令牌签发。有两种方式:使用我们的 React 组件库,或从任意框架直接调用认证 API。此功能需主动启用——请先在租户设置中启用自定义登录界面

前提条件:在您的根域名上启用自定义域名

登录会话是第一方 Cookie,因此您的界面与 Authagonal 认证服务器必须共享同一个可注册域名。请在与您应用运行所用的相同根域名下,将一个自定义认证域名指向 Authagonal——例如认证位于 login.acme.com,应用位于 app.acme.com。在存在已启用的自定义域名之前,自定义登录界面设置将保持禁用状态。

您的界面认证主机是否可用?
app.acme.comlogin.acme.com✅ 相同根域名
acme.comauth.acme.com✅ 相同根域名
app.acme.comacme.authagonal.io❌ 跨站点
myapp.iologin.acme.com❌ 跨站点

为什么必须使用自定义域名

跨站点的会话 Cookie 会成为第三方 Cookie——而浏览器(Safari、Chrome)正在逐步淘汰它。将认证保留在您自己的根域名下可使 Cookie 成为第一方且面向未来,这也是平台所强制的:跨域认证调用只有来自与认证主机共享根域名的来源时才会被接受。

此外,请将您界面的来源(例如 https://app.acme.com)添加到您 OAuth 客户端的允许的 CORS 来源中——与您为令牌交换设置的列表相同。

React:@authagonal/login

npm i @authagonal/login 将认证逻辑和界面作为同一个包提供——与 Authagonal 托管登录所基于的包相同。选择适合您的层级:

  • 完整应用——直接引入 App 并通过品牌设置为其设定主题。
  • 组合页面——在您自己的布局中使用 LoginPageMfaChallengePageResetPasswordPage
  • 基础组件 + 逻辑——使用 AuthLayout/Button/Input 和 API 客户端(loginmfaVerifyforgotPassword…)构建您自己的界面。
使用 @authagonal/login API 的自定义界面
import { AuthLayout, Input, Button, login, ApiRequestError } from '@authagonal/login';

function MyLogin() {
  async function onSubmit(email: string, password: string) {
    try {
      const res = await login({ email, password });        // POST /login (sets the session cookie)
      if (res.mfaRequired) {/* render your MFA step → mfaVerify(...) */}
      else window.location.href = res.returnUrl;            // hand off to /connect/authorize
    } catch (e) {
      if (e instanceof ApiRequestError) {/* show e.message */}
    }
  }
  return <AuthLayout>{/* your own markup + <Input/> <Button/> */}</AuthLayout>;
}

任意框架:调用认证 API

不使用 React?可直接调用认证流程端点(位于 /api/auth 下),然后移交给标准的 OIDC /connect/authorize 流程。请发送 credentials: 'include' 以便存储会话 Cookie。

端点用途
POST /api/auth/login进行身份验证;返回 mfaRequired 或返回 URL
POST /api/auth/register自助注册(启用时)
POST /api/auth/forgot-password发起密码重置
POST /api/auth/reset-password完成密码重置
GET /api/auth/password-policy密码策略(用于渲染规则)
POST /api/auth/mfa/*MFA 设置 + 验证(TOTP、WebAuthn、恢复码)

使用 credentials: 'include'

会话是一个 Cookie,因此您的请求必须发送凭据。跨域调用只有在启用了自定义登录界面,且您的来源与认证主机共享根域名时才会成功——否则将被以 403 拒绝。
先进行身份验证,然后移交给 OIDC
# 1. Authenticate (browser fetch — credentials:'include' so the session cookie is stored)
curl -i -X POST https://login.acme.com/api/auth/login \
  -H "Content-Type: application/json" \
  -H "Origin: https://app.acme.com" \
  --data '{"email":"jane@acme.com","password":"..."}'
# (handle {"mfaRequired":true} → POST /api/auth/mfa/verify, then continue)

# 2. Hand off to the OAuth flow — top-level navigation to the authorize endpoint with PKCE:
# https://login.acme.com/connect/authorize?client_id=my-app&redirect_uri=...&response_type=code
#   &scope=openid%20profile%20email&code_challenge=...&code_challenge_method=S256
# The session cookie (same-site) authenticates the user; you get back a code → exchange at /connect/token.

方案与限额

Authagonal 提供四个方案级别。所有方案包含所有功能——唯一的区别是月活跃用户(MAU)限额和超额定价。

方案级别

方案MAU 限额超额超额费用/用户
入门版1,000
专业版5,000$0.04/用户
规模版25,000$0.025/用户
企业版100,000$0.015/用户

月活跃用户(MAU)

月活跃用户是在计费月内至少成功完成一次身份验证的唯一用户。通过 SCIM 配置但尚未登录的用户不计入您的 MAU 总数。

超额——如果您的方案支持超额,超出 MAU 限额的用户将按上方方案表中显示的每用户费率计费。您可以设置超额上限以限制计费周期的最大支出。

强制执行——如果您的方案不支持超额(入门版),超出 MAU 限额的用户在下一个计费周期或您升级到支持超额的方案之前无法登录。

每个方案均包含完整功能

所有方案包含完整功能集——SSO、SCIM、MFA、自定义域名、品牌、Webhook、审计日志和门户。