Skip to content

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 保持一致
appIdOIDC Client ID不要硬编码多个环境,尽量由运行时配置下发
redirectUricallback 页面地址必须与控制台配置完全一致
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_at
  • addAccessTokenExpired(...) => redirect
  • addUserUnloaded(...) => redirect
  • if (!token) redirect('/login')

请统一基于 SDK 的:

  • auth.isLoading
  • auth.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',
});

返回字段重点

推荐重点关注:

  • tenant
  • user
  • application
  • organization
  • organizations
  • session

其中:

  • 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 行为是:

  1. /oidc/token 返回 invalid_grant
  2. SDK 清理本地登录态
  3. isAuthenticated 变成 false
  4. 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 中声明
  • 如果是组织后台,defaultOrganizationIdsignIn({ organizationId }) 策略明确
  • 项目实际使用的是最新 SDK 构建产物

常见问题

页面刷新后为什么会重新进登录态恢复

因为 SDK 会在初始化时执行 manager.getUser() 恢复本地用户状态。这是正常行为。

为什么不要自己根据 expires_at 跳登录页

因为 SDK 内部已经处理了短 TTL、自动续期和 refresh token 失效清理。第三方自己再做一层,最容易引入错误时序。

refresh token 过期后为什么没有自动跳到登录页

SDK 只负责切回未认证状态,不强行决定路由行为。请使用 CodeBirdAuthGuard 并在 onUnauthenticated 中调用 auth.signIn()

相关文档

Released under the MIT License.