跳到主要内容
版本:3.9.x

使用 Okta 为自定义开发者门户配置 SCIM 预配

SCIM(跨域身份管理系统)让 Okta 可以在基于 API7 Developer Portal Boilerplate v0.10.0 的自定义开发者门户中创建和更新身份。该集成会添加 Better Auth 服务端插件和数据库 schema;它不是一项用于在已发布前端镜像中启用端点的设置。

预配身份不会自动将用户加入门户组织、授予 API 产品访问权限,也不会撤销先前签发的网关凭证。在使用 SCIM 管理开发者访问权限之前,请将预配生命周期与自定义应用的授权模型集成。

SCIM 预配也不会配置交互式登录。插件会创建用户和 SCIM 提供商账户,但不会创建密码、会话或 OpenID Connect 登录。必须另行实现身份认证和账户关联,并验证登录映射到预期的 SCIM 用户。

前置条件​

  • 基于 Boilerplate v0.10.0 的自定义开发者门户;该版本声明 Better Auth ^1.6.11,发布时的锁定版本为 1.6.19。
  • 可用的门户身份认证数据库和身份认证路由。
  • 能登录自定义门户并生成 SCIM 凭据的管理员账户。
  • 已审查 SCIM 身份与交互式登录提供商之间的认证及账户关联设计。
  • 具有管理权限的 Okta 账户。

在 Okta 中创建 SCIM 应用程序​

在修改门户代码之前,请在 Okta 中创建 SCIM 应用程序。

  1. 登录 Okta Admin Console。
  2. 转到 Applications -> Applications。
  3. 单击 Browse App Catalog。
  4. 搜索 SCIM。
  5. 选择 SCIM 2.0 Test App (Header Auth)。
  6. 单击 Add Integration。
  7. 在 General Settings 中,为应用命名,例如 API7 Portal。
  8. 在 Sign-On Options 中,选择 Secure Web Authentication (SWA)。
  9. 单击 Done。

在 Okta 中搜索 SCIM 集成

配置常规设置

选择登录选项

安装并注册 SCIM 插件​

从 Boilerplate 工作区根目录安装 SCIM 1.6.19。该版本与锁定的 Better Auth 1.6.19、better-call 1.3.6 和 @better-auth/utils 0.4.2 依赖相匹配:

pnpm --filter @api7ee/site add \
@better-auth/scim@1.6.19 \
server-only@0.0.1

在 apps/site/src/lib/auth/server.ts 中导入插件,并将其添加到现有服务端插件列表。保留其他插件和钩子的原有顺序:

apps/site/src/lib/auth/server.ts
import { scim } from '@better-auth/scim';

export const auth = betterAuth({
// Keep the existing Better Auth options.
plugins: [
// Keep the existing plugins.
scim({
providerOwnership: { enabled: true },
storeSCIMToken: 'hashed',
beforeSCIMTokenGenerated: async ({ user }) => {
const roles = (user as typeof user & { role?: string }).role
?.split(',')
.map((role) => role.trim());
const isAdmin =
config.auth.adminUserIds.includes(user.id) || roles?.includes('admin');
if (!isAdmin) {
throw APIError.from('FORBIDDEN', {
code: 'SCIM_ADMIN_REQUIRED',
message: 'Only portal administrators can generate SCIM tokens',
});
}
},
}),
nextCookies(),
],
});

回调将 Token 生成权限限制为门户管理员。提供商所有权还会将后续的提供商管理和 Token 轮换限制为生成该 Token 的管理员。以哈希方式存储 Token,可以防止从身份认证数据库还原预配凭据。明文 Token 仅在生成时返回。

更新身份认证路由​

Boilerplate 路由最初只开放 GET 和 POST。SCIM 还会使用 PUT、PATCH 和 DELETE。请更新现有处理程序:

apps/site/app/api/(auth)/auth/[...all]/route.ts
import { auth } from '@/lib/auth/server';
import { toNextJsHandler } from 'better-auth/next-js';

export const { GET, POST, PUT, PATCH, DELETE } = toNextJsHandler(auth.handler);

应用数据库迁移​

在 apps/site/src/lib/db/schema.ts 中添加与版本匹配的 SCIM 提供商表,不要替换现有 Better Auth 表:

apps/site/src/lib/db/schema.ts
export const scimProviders = pgTable('scim_providers', {
id: text('id').primaryKey(),
providerId: text('provider_id').notNull().unique(),
scimToken: text('scim_token').notNull().unique(),
organizationId: text('organization_id'),
userId: text('user_id'),
});

生成并应用 Drizzle 迁移。react-server 条件让 Drizzle 能加载 Boilerplate 的仅服务端配置模块:

cd apps/site
NODE_OPTIONS='--conditions=react-server' pnpm db:generate
NODE_OPTIONS='--conditions=react-server' pnpm db:migrate

应用前审查生成的 SQL。对于未修改的 Boilerplate v0.10.0 schema,此次更改应创建 scim_providers 表,包括可选的所有者字段 user_id,不应有无关的表或列变更。运行迁移前删除或调查任何无关语句。

生成 SCIM Token​

创建临时服务端脚本,以管理员身份登录,并为 okta 提供商生成凭据:

apps/site/scripts/get-scim-token.ts
import { auth } from '@/lib/auth/server';

const email = process.env.SCIM_ADMIN_EMAIL;
const password = process.env.SCIM_ADMIN_PASSWORD;

if (!email || !password) {
throw new Error('SCIM_ADMIN_EMAIL and SCIM_ADMIN_PASSWORD are required');
}

async function main() {
const login = await auth.api.signInEmail({
returnHeaders: true,
body: { email: email!, password: password! },
});

const result = await auth.api.generateSCIMToken({
headers: {
cookie: login.headers.get('set-cookie') ?? '',
},
body: {
providerId: 'okta',
},
});

console.log(result.scimToken);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

从工作区根目录运行该脚本:

read -rp "Portal administrator email: " SCIM_ADMIN_EMAIL
read -rsp "Portal administrator password: " SCIM_ADMIN_PASSWORD && echo
export SCIM_ADMIN_EMAIL SCIM_ADMIN_PASSWORD

NODE_OPTIONS='--conditions=react-server' \
pnpm --filter @api7ee/site exec tsx scripts/get-scim-token.ts

unset SCIM_ADMIN_EMAIL SCIM_ADMIN_PASSWORD

将生成的 Token 保存到获准使用的密钥管理器,然后删除临时脚本。只有生成该提供商的门户用户才能管理其元数据或替换凭据。使用相同提供商 ID 再次生成 Token 会替换已存储的凭据,因此轮换后应立即更新 Okta。

配置 Okta API 集成​

  1. 在 Okta 中,打开 SCIM 应用的 Provisioning 选项卡。
  2. 单击 Configure API Integration。
  3. 启用 API 集成。
  4. 设置:
    • 将 SCIM 2.0 Base URL 设为 https://<YOUR_PORTAL_DOMAIN>/api/auth/scim/v2
    • 将 API Token 设为 Bearer <YOUR_SCIM_TOKEN>
  5. 单击 Test API Credentials。
  6. 如果测试成功,单击 Save。

配置 API 集成

配置预配并分配用户​

配置预配​

  1. 在 Provisioning 选项卡中,选择 To App。
  2. 单击 Edit。
  3. 启用你需要的功能:
    • Create Users
    • Update User Attributes
  4. 单击 Save。

不要启用 Deactivate Users。SCIM 插件 1.6.19 将 active 属性视为只读,在此基线中没有经过验证的 Okta 停用用户流程。允许身份提供商停用用户前,必须实现并测试兼容的取消预配流程。

启用创建用户

分配用户​

  1. 打开 Assignments 选项卡。
  2. 单击 Assign,然后选择 Assign to People 或 Assign to Groups。
  3. 选择要预配的用户或组。
  4. 单击 Assign,然后单击 Done。

分配给用户

验证预配​

在依赖此集成前,请验证受支持的生命周期:

  1. 分配测试用户,并确认门户身份认证数据库中创建了 SCIM 资源。
  2. 更改已分配的属性,并确认该 SCIM 资源得到更新。
  3. 通过单独配置的交互式登录提供商登录,确认账户关联映射到预期的 SCIM 用户,而不是创建重复账户。
  4. 测试单独的授权集成,确认预配身份映射到预期的门户组织、API 产品、订阅及凭据。

不要把 Okta 凭据测试或成功更新用户当作取消预配已生效的证明。应独立测试自定义的停用或删除流程,包括会话撤销和先前签发的 API 凭据如何处理。

验证数据库中的用户

后续步骤​