@faiber/faiber-idp

中文文档
2.8.0发布于 2026/11/14TypeScriptES Module近 30 天下载 3830

Authentication, sessions, users, roles, permissions, OAuth identities, and identity settings.

原始使用文档
文档目录14 节
  1. Install
  2. Configure
  3. Complete capability
  4. Authentication and authorization
  5. Inputs, queries, responses, and transport
  6. Errors and cancellation
  7. Handoff and current-user passwords
  8. OIDC service paths
  9. Current grants and active role membership
  10. Revisioned role permission changes
  11. Additive memberships and intentional replacement
  12. Native response and update behavior
  13. Role target visibility
  14. Explicit contact ownership

@faiber/faiber-idp

Authentication, sessions, users, roles, permissions, OAuth identities, and identity settings.

Install

npm install @faiber/faiber-idp

Configure

import { FaiberClient, MemoryTokenProvider } from "@faiber/sdk-core";
import { IdpApi } from "@faiber/faiber-idp";

const tokens = new MemoryTokenProvider();
const client = new FaiberClient("idp", {
  domains: { idp: process.env.FAIBER_IDP_URL! },
  tokenProvider: tokens,
  axios: { timeout: 15_000, withCredentials: true },
});
const api = new IdpApi(client);

const login = await api.login({
  grant_type: "password",
  username: "[email protected]",
  password: "secret",
  client_id: "2",
  client_secret: "client-secret",
  device_id: "my-stable-device-id",
});
await tokens.setTokens({
  accessToken: login.data.data.access_token,
  refreshToken: login.data.data.refresh_token,
});

Complete capability

This package exposes 114 mounted operations from the identity and access service. Common workflows have concise methods on api; every registered backend route is also available as a named function on api.operations. Generated operation input, query, response, path, verb, and permission contracts are exported from operations.types.

AreaOperationsHTTP methods
acl10DELETE, GET, PATCH, POST, PUT
auth27DELETE, GET, OPTIONS, POST
custom-oauth8DELETE, GET, POST, PUT
effective-permissions1GET
identity-authority10GET, POST, PUT
integration1GET
oauth-clients6DELETE, GET, POST, PUT
oidc11GET, POST
router2GET
settings7GET, POST, PUT
visibility6GET, POST, PUT
user27DELETE, GET, PATCH, POST, PUT

Legacy token login, web login, account login, and OTP login are encoded as application/x-www-form-urlencoded. api.operations.authBrowserLoginPost accepts a registered public client, a password or OTP credential, and a matching HTTPS Origin; it returns an HttpOnly session cookie without a client secret or bearer token in the response. Persist and reuse a stable, non-secret device_id for legacy token login so the IDP can distinguish physical devices. Use api.sessions() to list active sessions and api.revokeSession(sessionId) to revoke one. Role assignment uses role UUIDs.

Authentication and authorization

Use a TokenProvider to forward the signed-in user's Bearer token, or enable withCredentials for secure HttpOnly cookie sessions. Native handler permission and credential requirements are documented in each operation's JSDoc. Protected user and ACL calls revalidate active native principal, client and session state. The SDK does not embed API keys, credentials, localhost URLs, sandbox hosts, or production hosts.

Inputs, queries, responses, and transport

All methods return the complete Axios response, including status, headers, and request IDs. Request bodies and query objects are named exported interfaces. Managed user pagination uses native page and per_page keys (defaults 1 and 20; at most 100 per page). Linked billing uses page and page_size. User-directory search requires at least three trimmed characters and returns at most ten masked matches. Standard Axios request options, headers, timeouts, adapters, interceptors, and AbortSignal cancellation are supported as the final argument.

Generic REST resources are capability-guarded. Calling a legacy method that the service does not register throws UnsupportedOperationError before sending a request instead of producing a backend 405.

Errors and cancellation

try {
  await api.client.get("/health", undefined, { signal: AbortSignal.timeout(5_000) });
} catch (error) {
  // Axios errors retain response.status and the service error body.
}

Use @faiber/faiber-ts-sdk when one application needs multiple Faiber services with one configuration.

Managed user responses include created_at, the UTC registration timestamp, nullable display_name, and linked_providers. Registration statistics remain available through the typed user registration-stats operation.

Handoff and current-user passwords

operations.authExchangeHandoffTokenPost({token, client_id}) consumes a single-use handoff code and returns a token envelope. authIssueHandoffTokenPost is server-only and requires x-infera-handoff-secret; never put that secret into browser code. authOtpLoginPost sends its named input as URL-encoded form data, including otp_code.

operations.userStatusGet() returns {data:{has_password}}. userSavePut({password}) replaces only the authenticated account's password and preserves OAuth identities; passwords must contain 8–128 characters. Website OAuth bootstrap accepts a canonical HTTPS origin and requires an administrator or the trusted federation service.

OIDC service paths

Discovery uses /.well-known/openid-configuration; authorization, token, user-info, JWKS, revocation, introspection and logout use /oauth2/* at the service root. These paths do not have an /api/v1 prefix. The generated OIDC methods use the shared client and form-encode token/revocation inputs. Internal single-use token generation requires the target user UUID in the URL. Pass the server-only x-infera-idp-service-token header for the current identity project and the configured internal Host. Host alone is rejected. Missing/invalid credentials return 401; missing credential configuration fails closed with 503. Never expose project credentials or the platform derivation seed in a browser.

Current grants and active role membership

api.authority.currentPermissions(userId, { service }) reads current grants from that IDP. It requires both idp:user:read and idp:acl:read; its revision and observation time do not grant resource access or justify caching permissions. The consuming service must still enforce ownership and current permissions. service is the actual stored IDP permission namespace; for Messenger this is message, which must not be inferred from the SDK package name.

api.authority.activeRoleUsers({ role_name, page, per_page }) requires idp:user:read and always requests enabled accounts with current active membership in the exact, case-sensitive native role name. Optional role_id must identify the same role. It preserves the full Axios response and supports AbortSignal, timeouts and normal authentication options.

const controller = new AbortController();
const response = await api.authority.activeRoleUsers(
  { role_name: 'reviewer', page: 1, per_page: 25 },
  { signal: controller.signal },
);
const members = response.data.data.users;

These methods require an IDP that implements the current grant and role-filter contracts. activeRoleUsers checks the native filter acknowledgement and returned active membership, throwing IdpRoleFilterError with code idp_role_filter_unconfirmed when the server does not confirm the scope. It makes no unfiltered fallback request. Native HTTP and authentication failures remain Axios errors. Pagination is bounded to 100 users per page, and IDP clamps requests beyond the last page.

Revisioned role permission changes

Read api.authority.roleGrants(roleId) using idp:acl:read, review the returned permissions, then call api.authority.changeRoleGrants(roleId, { expected_revision: snapshot.revision, add: [permissionId], remove: [] }) with both idp:acl:read and idp:acl:update. Use the native role and permission UUIDs. This atomically preserves unrelated grants. The full Axios response retains status, request headers and private no-store caching policy. The revision is a conflict token, never a delegated credential or permission cache.

A stale revision returns409: fetch a new snapshot and explicitly review/rebase the intended changes. Never retry automatically with a new revision. Invalid, inactive or duplicate additions and overlapping add/remove sets return400; the built-in admin role is protected406. Combined additions/removals are limited to max_delta_entries (currently4096). Unavailable/oversized snapshots return503. Signals, timeouts and authentication use the shared client options. The legacy role replacement methods intentionally replace the entire permission set and must not be used for a minimal additive change. Mixed older service writers must be quiesced during deployment; rolling back a grant requires a fresh reviewed revision and removal of only the addition still owned by that operation.

Additive memberships and intentional replacement

roleMemberships(userId) reads all stored membership rows, including inactive and duplicate rows, with an opaque observed revision. addRoleMemberships(userId, { add_role_ids }) adds 1–128 unique active local role UUIDs to an already active local user. It preserves existing memberships; it never activates an account. The server rechecks current read/update ACL authority under the target lock. Both calls return the complete Axios response.

await api.addRoleMemberships(userId, { add_role_ids: [reviewerRoleId] });
const observed = (await api.roleMemberships(userId)).data.data;
// Only for an intentional full replacement reviewed against this exact snapshot:
await api.changeRoles(userId, { roles: reviewedRoleIds }, observed.revision);

Replacement helpers, including generated PATCH/PUT operations, require the captured revision and send it as quoted If-Match. A stale revision returns 409; missing backend preconditions return 428. Refresh the review after a conflict. Never fetch a new revision merely to submit a saved stale role union. This SDK does not do that automatically. The IDP audit migration and backend activation require their separate release gates.

Native response and update behavior

login, accountLogin, otpLogin, and refresh return token envelopes. webLogin, logout, and revokeSession return only {status, message}. providers() returns {data:{providers:string[]}}; register() returns {data:{user:{user_id, created}}}. User deletion and forced user logout return data.user, while role deletion returns data.id and data.name.

Managed users.update/users.replace and updateUser clear omitted, null, or empty identifier fields in this backend. Include every phone, email and national code value you intend to retain. Self identifier updates only fill missing identifiers; they reject replacement of an existing value with 409.

The legacy administrative changePassword operation removes all local identity rows before inserting the new password identity. The current-user operations.userSavePut operation preserves other login identities. Its accepted current_password field is not checked by this backend; a current active session authorizes replacement.

OIDC and native authorization, OAuth callback, token-login and browser handoff operations return HTTP redirects. Browser clients generally navigate to these authorization URLs; an Axios call may follow a redirect and receive the destination page. OIDC token/user-info/discovery/JWKS/introspection responses are raw JSON. Logout/back-channel logout return empty 204 and revocation returns empty 200. Login-page asset download returns bytes with Axios responseType: "arraybuffer"; uploads require the first multipart field to be named file, PNG/JPEG/WebP with a matching signature, and 1 byte–8 MiB.

Public registration rejects role assignment; use managed creation or the reviewed membership workflow. Full membership replacement requires idp:acl:update and the captured revision; reading a snapshot requires idp:acl:read, and additive membership updates require both. The users/sync handler has no session/ACL guard and triggers downstream publication; deployment gateway policy determines its exposure.

Role target visibility

Read sdk.idp.visibility.roleScope(roleId) and save one common target-role list:

const { data: response } = await sdk.idp.visibility.roleScope(supportRoleId);
await sdk.idp.visibility.saveRoleScope(supportRoleId, {
  revision: response.data.revision,
  target_role_ids: [studentRoleId, teacherRoleId],
}, { signal: abortController.signal });

Management requires idp:visibility:assign. Normal YAML-backed permissions separately control read, edit, delete, password changes and other actions. Saving this scope never changes those permissions. null removes the role's limit; [] allows no targets. Configured scopes combine across active actor roles; unconfigured roles and direct permissions cannot remove a configured limit. If no role has a configured scope, existing permissions retain unrestricted target access. The role catalog is fully dynamic.

The revision is required; reload and review after HTTP 409, and handle invalid UUIDs as HTTP 422. Responses retain Axios metadata and shared authentication/cancellation. The old .rules/.save action-grant methods are deprecated; use .roleScope/.saveRoleScope. Deploy the corresponding IDP role-target-scope backend before using these methods.

Explicit contact ownership

contactVerification.facts(userId, options) is a backend-only integration. Configure the service Bearer credential through the shared transport; never ship it to a browser. It returns the standard envelope with user_id and contact_verified, without exposing contact values. A populated contact field or active account is insufficient: the current contact must match a recorded successful OTP or explicit verified assertion from a trusted OAuth provider. Changing contacts invalidates the old match. Treat outages as unverified.

版本与发布记录

@faiber/faiber-idp 共发布 66 个版本,首次发布于 2026/07/18;过去 12 个月发布了 66 个版本。

版本发布日期距今
2.8.0latest2026/11/14今天
2.7.02026/11/059 天前
2.6.02026/11/049 天前
2.5.02026/11/049 天前
2.4.02026/11/0310 天前
2.3.02026/11/0211 天前

关于 @faiber/faiber-idp 的常见问题

@faiber/faiber-idp 是什么?

Authentication, sessions, users, roles, permissions, OAuth identities, and identity settings.

如何安装 @faiber/faiber-idp?

在项目目录运行 npm install @faiber/faiber-idp,或使用 pnpm add / yarn add / bun add。

@faiber/faiber-idp 支持 TypeScript 吗?

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

@faiber/faiber-idp 支持 ESM 还是 CommonJS?

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

@faiber/faiber-idp 可以商用吗?

@faiber/faiber-idp 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@faiber/faiber-idp 的下载量有多少?

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

@faiber/faiber-idp 还在维护吗?

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