使用 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 应用程序。
- 登录 Okta Admin Console。
- 转到 Applications -> Applications。
- 单击 Browse App Catalog。
- 搜索
SCIM。 - 选择 SCIM 2.0 Test App (Header Auth)。
- 单击 Add Integration。
- 在 General Settings 中,为应用命名,例如
API7 Portal。 - 在 Sign-On Options 中,选择 Secure Web Authentication (SWA)。
- 单击 Done。



安装并注册 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 中导入插件,并将其添加到现有服务端插件列表。保留其他插件和钩子的原有顺序:
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。请更新现有处理程序:
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 表:
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 提供商生成凭据:
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 集成
- 在 Okta 中,打开 SCIM 应用的 Provisioning 选项卡。
- 单击 Configure API Integration。
- 启用 API 集成。
- 设置:
- 将 SCIM 2.0 Base URL 设为
https://<YOUR_PORTAL_DOMAIN>/api/auth/scim/v2 - 将 API Token 设为
Bearer <YOUR_SCIM_TOKEN>
- 将 SCIM 2.0 Base URL 设为
- 单击 Test API Credentials。
- 如果测试成功,单击 Save。
