@bsuite/auth

中文文档
1.0.1发布于 2026/09/18UNLICENSEDTypeScriptES Module近 30 天下载 2318

BSuite OAuth 2.1 PKCE客户端——共享于CRM7,R80.4,布拉登,康杜特,和通通. 使用 JWKS 通过 jose 进行符号验证 .

中文使用文档
文档目录11 节
  1. 同步登录和召回恢复
  2. OAuth 服务器环境
  3. 安装
  4. 使用量
  5. API 密码
  6. 行为说明
  7. 存储密钥
  8. 设计说明
  9. Per- app OAuth 客户端标识
  10. 相关文件
  11. 许可证

@ bsuite/ auth (英语)

OAuth 2.1 PKCE客户端在BSuite应用程序(CRM7, Conduit, R80.4, Braden, Turput)之间共享. BSU是 OAuth 服务器;这个软件包是用于消耗它的其他应用程序的客户端.

同步登录和召回恢复

选入 届会所有权协调员 序列化 消费者SDK在同源标签上写作和登录。 消费者适配器接线, 交易快照约束和部署的核查仍然是必要的.

登录启动器应当使用 attemptSilentAuthDetailed()。继续使用 authenticated; 暂停 redirecting 或者说 superseded; 提供交互式恢复 failed。旧布尔帮助器仍然兼容,但无法区分预定导航和失败。 指派 window.location 不停止后续的 JavaScript .

路由调用 hasPendingBusinessSuiteTransaction(state),这需要这个来源的完整,新的交易状态. 不从状态形状或存在不相关的后遗症键发送 。 遗产交易还需要其核查人、非记录和时间戳。 交易不完全需要新的签注 .

BusinessSuiteOAuthExchangeUncertainError.recovery 实值 fresh-sign-in:服务器可能在网络或响应-body故障前消耗了单用代码. 永远不要自动重放它。 回调错误处理器必须保存不相关的交易和较新的会话. 在开始交换之前抓取消费者的会话/日志生成器,并在核实后以及在进行信使或导航之前再次检查。 已经在飞行中的交换可以在签出后返回;其结果不得恢复上一个会话. 成功交换后,通过消费者的桥梁 supabase.auth.setSession() 在保护数据读取之前。 主机-本地会话存储仍然与跨应用 OAuth SSO 分离.

套件是故意小的——它默认生产出BSuite Supabase主机(https://tuybltdrdefjblnplpqo.supabase.co),支持针对持续开发的Supabase分支的 OAuth-server 明确覆盖,解决从 URI重定向 VITE_APP_URL (或 NEXT_PUBLIC_APP_URL)在有可用的情况下,并回到 ${window.location.origin}/auth/callback它只取决于 jose jWKS验证.

OAuth 服务器环境

生产消费者不需要额外的配置;OAuth服务器默认为生产出BSuite Supabase项目. 使用持续Supabase分支/项目的长期开发部署,必须设定该分支URL的其中一个变量:

  • VITE_BSU_OAUTH_SUPABASE_URL 用于构建 Vite 浏览器
  • NEXT_PUBLIC_BSU_OAUTH_SUPABASE_URL next.js 浏览器构建
  • BSU_OAUTH_SUPABASE_URL 用于服务器/构建时环境

接受的别名是 VITE_BUSINESS_SUITE_SUPABASE_URL, (中文(简体) ), NEXT_PUBLIC_BUSINESS_SUITE_SUPABASE_URL,以及 BUSINESS_SUITE_SUPABASE_URL。数值必须是表格中的 HTTPS Supabase 项目 URL https://<project-ref>.supabase.co;在将用户重定向到破损的 OAuth 流之前,无效的覆盖 .

安装

pnpm add @bsuite/auth

使用量

每个消费者应用都创建了薄薄的包装器,将共享的客户端再出口到其OAuth客户端ID上. 从CRM7中取出的例子(犬科参考文献——相同模式 R80.4, (中文(简体) ), braden, (中文(简体) ), conduit, (中文(简体) ), throughput:

// src/lib/business-suite-oauth.ts
import { createOAuthClient } from '@bsuite/auth';
export type { BusinessSuiteTokens, VerifiedUser } from '@bsuite/auth';

export const {
  signInWithBusinessSuite,
  exchangeCodeForTokens,
  refreshBusinessSuiteToken,
  verifyAccessToken,
  getUserInfo,
  clearBSTokens,
  startBSTokenRefresh,
  attemptSilentAuthDetailed,
} = createOAuthClient('30f76744-3e0b-40bf-abb8-8c587389802e'); // your app's OAuth client ID

然后把它接入授权的生命周期:

// On a login button click — schedules navigation to the OAuth server
void signInWithBusinessSuite();

// In your /auth/callback route, with `code` and `state` parsed from the URL
const { tokens, user } = await exchangeCodeForTokens(code, state);
localStorage.setItem('bs_access_token', tokens.access_token);
localStorage.setItem('bs_refresh_token', tokens.refresh_token);
localStorage.setItem('bs_user', JSON.stringify(user));
if (tokens.id_token) localStorage.setItem('bs_id_token', tokens.id_token);

// On app mount (e.g. AuthContext / AuthProvider) — try OIDC silent re-auth before showing the login UI
const result = await attemptSilentAuthDetailed();
// Stop on redirecting/superseded; navigate only on authenticated.

// Start the auto-refresh loop and capture the cleanup function
const stopRefresh: () => void = startBSTokenRefresh();
// later, e.g. on AuthContext unmount or sign-out:
stopRefresh();

// Sign-out — clear all 4 BS OAuth localStorage keys
clearBSTokens();

API 密码

import type { OAuthClient, BusinessSuiteTokens, VerifiedUser } from '@bsuite/auth';

declare function createOAuthClient(clientId: string): OAuthClient;

interface OAuthClient {
  signInWithBusinessSuite(): Promise<void>;
  exchangeCodeForTokens(
    code: string,
    state: string,
  ): Promise<{ tokens: BusinessSuiteTokens; user: VerifiedUser }>;
  refreshBusinessSuiteToken(
    refreshToken: string,
  ): Promise<{ tokens: BusinessSuiteTokens; user: VerifiedUser }>;
  verifyAccessToken(token: string): Promise<VerifiedUser>;
  getUserInfo(accessToken: string): Promise<Record<string, unknown>>;
  clearBSTokens(): void;
  startBSTokenRefresh(): () => void; // returns a cleanup function
  attemptSilentAuth(): Promise<boolean>;
}

interface BusinessSuiteTokens {
  access_token: string;
  refresh_token: string;
  token_type: string;
  expires_in: number;
  id_token?: string;
}

interface VerifiedUser {
  sub: string;
  email?: string;
  name?: string;
  picture?: string;
  client_id?: string;
  role?: string;
}

行为说明

  • signInWithBusinessSuite 生成 PKCE code_verifier, (中文(简体) ), code_challenge (S/256), (中文(简体) ), state,和OIDC nonce,将其储存在 localStorage 带10分钟TTL哨,然后设定 window.location.href 向《争端解决协议》提交的报告 /auth/v1/oauth/authorize URL (中文(简体) ). 返回的"承诺"从不解决——页面通航.
  • exchangeCodeForTokens 验证 state (CSRF),读取存储的PCE验证器,帖子到 /auth/v1/oauth/token,然后JWKS-验证访问符和OIDC id_token 非ce(每个OIDC Core § 3.1.2.2的重播保护). 扔出状态不匹配,缺少验证器,非-2xx响应,或非ce不匹配.
  • refreshBusinessSuiteToken 员额 /auth/v1/oauth/token 与 grant_type=refresh_token 并在返回前通过JWKS验证新的访问符.
  • verifyAccessToken 使用缓存 JWKS (jose是因为 createRemoteJWKSet与 issuer: "<supabase>/auth/v1" 财务报告和审定财务报表 audience: "authenticated". 仅RS256/ES256.
  • getUserInfo 开始 /auth/v1/oauth/userinfo 与提供的无记名标志 并返回解析的JSON尸体.
  • startBSTokenRefresh 立即进行检查,然后每60秒进行一次民意测验,并在到期前5分钟刷新标志. 返回一个停止间隔的清理函数. 总是抓取清理 以避免在挂载/卸载组件(例如AuthProvider)中泄漏定时器.
  • attemptSilentAuth 返回时 true 如果在 localStorage 中已经存在有效的访问令牌,或者有一个可以成功交换的刷新令牌. 回返 false 否则。 永不抛出——错误被吞入,所以登录UI仍然可以渲染出.
  • clearBSTokens 删除 bs_access_token, (中文(简体) ), bs_refresh_token, (中文(简体) ), bs_user, (中文(简体) ), bs_id_token 从本地Storage。 总是打电话签到.

存储密钥

存储密钥目的终身
localStoragebs_access_tokenJWT 访问符 (JWKS- 验证)直到刷新/ 签出
localStoragebs_refresh_token刷新符号直到刷新/ 签出
localStoragebs_userJSON 序列化 VerifiedUser直到刷新/ 签出
localStoragebs_id_tokenOIDC id token (可选)直到刷新/ 签出
localStoragebs_oauth_code_verifierPKCE 代码验证器仅登录入流, TTL 守护
localStoragebs_oauth_stateCSRF 状态仅登录入流, TTL 守护
localStoragebs_oauth_nonceOIDC 重放保护非ce仅登录入流, TTL 守护
localStoragebs_oauth_started_atPKCE TTL 监视器仅输入流程
localStoragebs_oauth_flows国有证券交易十分钟/完成/退出
localStoragebs_oauth_inflight_codes具有所有者身份的每个编码索偿十分钟/完成/退出

设计说明

  • 每个域 localStorage ——道具从不离开应用的自产地. 通过OIDC实现跨应用SSO prompt=none 静静地重现( s)attemptSilentAuth),非跨域饼干. 堕落者 business_suite_auth cookie SSO计划被删除了 2025-02-27; 不要重新引入.
  • JWKS 验证 —— 说 verifyAccessToken 获取 Supabase /.well-known/jwks.json 一次并缓存它通过 jose是因为 createRemoteJWKSet. 仅RS256/ES256.
  • 第256号强制性规定 ——没有隐性流动,没有 plain 挑战.
  • OIDC 非ce 验证 如果 id_token 返回时,其 nonce 在匹配的按国家键交易(或符合资格的遗留交易)中,对索赔进行非ce核查。 缺失或错配的非ce会投出"id token noce错配——可能的回放攻击"(OIDC Core §3.1.2.2).
  • 托肯过期事件 如果自动更新回路失败, 或删除了兄弟姐妹标签 bs_access_token,包发送 a bs-oauth-expired CustomEvent 打开 window 因此,应用程序可以在令牌被清除之前做出反应(例如显示一面横幅). 原因: network_error, (中文(简体) ), refresh_rejected, (中文(简体) ), cross_tab_logout。 。 。 .

Per- app OAuth 客户端标识

应用客户身份
风险管理730f76744-3e0b-40bf-abb8-8c587389802e
第80.3号公路5d804d20-cd1b-4724-9107-86d2a9e51e09
布莱登dcb7af18-254a-4946-b94d-5c606b01fc3f
吞吐量35f0db49-ef62-4115-baba-7b961f034cc3
管道da925c19-8f32-40a0-b74d-4eb9540c422f
  • 父复方舟认证架构 : AUTH_CANONICAL.md
  • 每个应用的整合:每个消费者的 src/lib/business-suite-oauth.ts

许可证

UNLICENSED(只使用内部套件).

版本与发布记录

@bsuite/auth 共发布 14 个版本,首次发布于 2026/04/20;过去 12 个月发布了 14 个版本。

版本发布日期距今
1.0.1latest2026/09/181 个月前
1.0.1-next.1next2026/09/091 个月前
1.0.1-next.02026/09/091 个月前
1.0.02026/08/182 个月前
0.2.82026/08/053 个月前
0.2.72026/07/064 个月前

关于 @bsuite/auth 的常见问题

@bsuite/auth 是什么?

BSuite OAuth 2.1 PKCE客户端——共享于CRM7,R80.4,布拉登,康杜特,和通通. 使用 JWKS 通过 jose 进行符号验证 .

如何安装 @bsuite/auth?

在项目目录运行 npm install @bsuite/auth,或使用 pnpm add / yarn add / bun add。

@bsuite/auth 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@bsuite/auth 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@bsuite/auth 可以商用吗?

@bsuite/auth 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@bsuite/auth 的下载量有多少?

根据 npm 官方下载统计,@bsuite/auth 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,318 次,日均约 77 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bsuite/auth 还在维护吗?

最新版本 1.0.1 发布于 2026/09/18(1 个月前);至今共发布 14 个版本,其中过去 12 个月发布了 14 个;首次发布于 2026/04/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。