React SDK 集成教程
本文档是当前 React SPA 接入 Code Bird Cloud 的官方最佳实践。
目标读者:
- 第三方前端工程师
- React SPA 项目负责人
- 需要接入统一登录、Token 自动续期、实时会话上下文和账户中心的业务团队
本文默认你使用官方 React SDK:
@codebird/react
本文覆盖的能力
本文会完整说明下面这些能力应该如何接:
- 初始化
CodeBirdProvider - 发起登录
- callback 页面处理
- 官方认证守卫
- Access Token 获取与自动续期
- 实时会话上下文
- 账户中心跳转
- 租户化终端用户入口
- refresh token 过期后的未认证处理
当前推荐的接入原则
推荐
- 用
@codebird/react统一承接前端认证 - 让 SDK 负责 token 刷新、状态恢复和本地 user 持久化
- 所有业务 API 请求前,通过 SDK 获取 Access Token
- 需要最新数据库状态时,通过 SDK 获取实时会话上下文
- 用官方
CodeBirdAuthGuard管理未认证态
不推荐
- 前端自己维护
oidc-client-ts UserManager - 前端自己直调
/oidc/token - 前端自己写 token 过期判断
- 前端自己监听 token 过期后清本地状态
- 前端自己拼裸
/sign-in、裸/register、裸/account-center/...
前置条件
- React 19
- 你已经创建了 SPA 类型应用
- 已配置 Redirect URI
- 已配置 Post Logout Redirect URI
- 已配置业务 API 对应的
resource - 如果是组织后台,已明确组织上下文策略
推荐准备这些运行时参数:
json
{
"issuer": "https://auth.codebird.cloud",
"appId": "YOUR_APP_ID",
"redirectUri": "https://app.example.com/callback",
"postLogoutRedirectUri": "https://app.example.com/login",
"resource": "https://api.example.com",
"organizationId": "org_123",
"configVersion": "admin-auth-v4",
"scopes": [
"openid",
"profile",
"email",
"offline_access",
"urn:codebird:scope:organizations",
"urn:codebird:scope:organization_roles"
]
}第 1 步:安装 SDK
bash
pnpm add @codebird/react版本建议见:
第 2 步:初始化 CodeBirdProvider
推荐使用后端运行时配置接口下发认证参数,再初始化 Provider。
tsx
import { useEffect, useState } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { CodeBirdProvider } from '@codebird/react';
import App from './App';
type RuntimeAuthConfig = {
issuer: string;
appId: string;
redirectUri: string;
postLogoutRedirectUri: string;
resource: string;
organizationId?: string;
configVersion: string;
scopes: string[];
};
export default function AuthBootstrap() {
const [config, setConfig] = useState<RuntimeAuthConfig | null>(null);
useEffect(() => {
void fetch('/api/v1/admin/app/init')
.then((response) => response.json())
.then((payload) => setConfig(payload.result));
}, []);
if (!config) {
return <div>Loading...</div>;
}
return (
<CodeBirdProvider
endpoint={config.issuer}
appId={config.appId}
redirectUri={config.redirectUri}
postLogoutRedirectUri={config.postLogoutRedirectUri}
defaultResource={config.resource}
defaultOrganizationId={config.organizationId}
configVersion={config.configVersion}
scopes={config.scopes}
automaticSilentRenew={false}
onError={(error) => {
console.error('[codebird-auth]', error);
}}
>
<BrowserRouter>
<App />
</BrowserRouter>
</CodeBirdProvider>
);
}参数说明
| 参数 | 含义 | 最佳实践 |
|---|---|---|
endpoint | 认证中心地址 | 与后端 Issuer 保持一致 |
appId | OIDC Client ID | 不要硬编码多个环境,尽量由运行时配置下发 |
redirectUri | callback 页面地址 | 必须与控制台配置完全一致 |
postLogoutRedirectUri | 登出后跳回地址 | 建议指向业务系统登录入口或首页 |
defaultResource | 业务 API 的 resource indicator | 必须与后端 Audience 完全一致 |
defaultOrganizationId | 当前默认组织 | 单组织后台可以直接固定 |
configVersion | 本地认证配置版本 | 变更 OIDC 参数时建议递增 |
scopes | 登录申请的 scope 列表 | 通常至少包含 openid profile email offline_access |
第 3 步:配置 callback 页面
tsx
import { Route, Routes } from 'react-router-dom';
import { CodeBirdCallback } from '@codebird/react';
import DashboardPage from './DashboardPage';
export default function App() {
return (
<Routes>
<Route path="/" element={<DashboardPage />} />
<Route path="/callback" element={<CodeBirdCallback />} />
</Routes>
);
}CodeBirdCallback 已经负责:
- 处理授权码回调
- 读取并恢复用户态
- 更新本地存储中的用户对象
业务代码不要在 callback 页自己再调 /oidc/token。
第 4 步:配置官方认证守卫
这是当前推荐的写法,尤其适合第三方项目。
tsx
import { CodeBirdAuthGuard, useCodeBirdAuth } from '@codebird/react';
function ProtectedShell() {
const auth = useCodeBirdAuth();
return (
<CodeBirdAuthGuard
loadingFallback={<div>Loading...</div>}
unauthenticatedFallback={<div>Redirecting...</div>}
onUnauthenticated={() => auth.signIn()}
>
<AppRoutes />
</CodeBirdAuthGuard>
);
}为什么推荐官方守卫
因为当前 SDK 已经统一处理了:
- 页面刷新后的本地登录态恢复
- Access Token 自动续期
- refresh token 失效后的本地登录态清理
如果第三方自己再包一层守卫,最常见的问题是:
- 在
isLoading还没结束时过早跳到登录页 - 自己根据
expires_at判断 token 过期 - 自己监听 token 过期事件后把用户踢掉
- refresh 成功后,页面仍因为外部守卫逻辑错误被跳走
强约束
第三方不要再自己写这些逻辑:
Date.now() > expires_ataddAccessTokenExpired(...) => redirectaddUserUnloaded(...) => redirectif (!token) redirect('/login')
请统一基于 SDK 的:
auth.isLoadingauth.isAuthenticated
第 5 步:发起登录
固定单组织后台
tsx
import { useCodeBirdAuth } from '@codebird/react';
export function LoginButton() {
const auth = useCodeBirdAuth();
return (
<button disabled={auth.isLoading} onClick={() => void auth.signIn()}>
前往统一身份认证登录
</button>
);
}运行时传组织
ts
await auth.signIn({
organizationId: 'org_123',
});第 6 步:请求业务 API
所有业务 API 请求前,都通过 SDK 取 token。
tsx
import { useCodeBirdAuth } from '@codebird/react';
export function ProfileButton() {
const auth = useCodeBirdAuth();
async function loadProfile() {
const token = await auth.getAccessToken();
const response = await fetch('/api/v1/admin/auth/me', {
headers: {
Authorization: `Bearer ${token}`,
},
});
const result = await response.json();
console.log(result);
}
return <button onClick={() => void loadProfile()}>加载当前用户</button>;
}getAccessToken() 的当前行为
当前 React SDK 已经负责:
- 判断当前 Access Token 是否存在
- 判断当前 token 的
aud是否匹配目标resource - 判断 token 是否已过期或即将过期
- 必要时自动执行
refresh_token + resource续期
这意味着第三方不需要自己做:
aud检查- token 过期判断
- 手动 refresh queue
第 7 步:使用实时会话上下文
当你需要数据库最新状态时,不要只看 claims。
适合使用实时上下文的场景:
- 管理员在后台改了用户资料
- 用户已被移出组织
- 组织管理员身份已变化
- 页面需要渲染最新组织列表
命令式调用
ts
const context = await auth.getSessionContext({
organizationId: 'org_123',
});Hook 调用
tsx
const { data, loading, error, refresh } = useSessionContext({
organizationId: 'org_123',
});返回字段重点
推荐重点关注:
tenantuserapplicationorganizationorganizationssession
其中:
tenant.slug是终端用户租户化入口的标准标识organization.is_admin是当前组织管理员的实时状态
第 8 步:租户化终端用户入口
如果第三方系统需要主动打开终端用户页面,不要再手工拼裸路径。
ts
const signInUrl = auth.buildTenantSignInUrl('tenant-demo');
const registerUrl = auth.buildTenantRegisterUrl('tenant-demo');
const forgotPasswordUrl = auth.buildTenantForgotPasswordUrl('tenant-demo');对应结果:
/t/{tenantSlug}/sign-in/t/{tenantSlug}/register/t/{tenantSlug}/forgot-password
注意
tenantSlug不能为空- 这组 helper 只用于终端用户入口
- 账户中心优先使用
openAccountCenter(),不要自己拼 URL
第 9 步:打开账户中心
ts
await auth.openAccountCenter();也可以指定目标页和组织:
ts
await auth.openAccountCenter({
target: 'security',
organizationId: 'org_123',
});当前 SDK 会自动:
- 确保当前 access token 可用
- 调用
/api/account/sso-ticket - 打开后端返回的租户化账户中心地址
Token 生命周期最佳实践
Access Token 快过期时会怎样
SDK 会提前判断 token 是否还能安全使用。
当前策略:
- 不是“每次请求都刷新”
- 只有 token 已过期、aud 不匹配,或进入提前刷新窗口,才会 refresh
Refresh Token 过期时会怎样
当前 SDK 行为是:
/oidc/token返回invalid_grant- SDK 清理本地登录态
isAuthenticated变成false- 由
CodeBirdAuthGuard触发重新登录
所以推荐的体验不是“把错误打到页面上”,而是:
- SDK 负责切回未认证状态
- 第三方用 Guard 自动重新登录
当前已知最佳实践
推荐
- 统一走
CodeBirdProvider - 统一走
CodeBirdAuthGuard - 统一通过 SDK 取 token
- 实时权限判断走
/api/session/context - 用
tenant.slug处理租户化入口
不推荐
- 自己保存 refresh token 直调
/oidc/token - 自己在业务层缓存 Access Token
- 自己拼
/account-center/... - 自己定义“未认证态页面”但不发起重新登录
联调清单
前后端联调前至少确认下面几项:
defaultResource与业务后端Audience完全一致redirectUri与控制台配置完全一致postLogoutRedirectUri可回到业务系统offline_access已在 scopes 中声明- 如果是组织后台,
defaultOrganizationId或signIn({ organizationId })策略明确 - 项目实际使用的是最新 SDK 构建产物
常见问题
页面刷新后为什么会重新进登录态恢复
因为 SDK 会在初始化时执行 manager.getUser() 恢复本地用户状态。这是正常行为。
为什么不要自己根据 expires_at 跳登录页
因为 SDK 内部已经处理了短 TTL、自动续期和 refresh token 失效清理。第三方自己再做一层,最容易引入错误时序。
refresh token 过期后为什么没有自动跳到登录页
SDK 只负责切回未认证状态,不强行决定路由行为。请使用 CodeBirdAuthGuard 并在 onUnauthenticated 中调用 auth.signIn()。
