# @descope/node-sdk 中文文档

规范地址：https://npmcn.com/package/%40descope/node-sdk/

版本：2\.22\.0
npm 元数据更新时间：2026-11-11T09:47:13.980Z
中文译文更新时间：2026-11-12T00:49:25.583Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40descope/node-sdk
原文对照：https://npmcn.com/package/%40descope/node-sdk/?lang=original
项目主页：https://github.com/descope/node-sdk#readme
源码仓库：https://github.com/descope/node-sdk

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：919 kB，9 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>= 18\.0\.0
- 运行依赖：3 个
- 首次发布：2022-08-16T09:27:42.623Z
- 最新版本发布：2026-11-11T09:47:13.583Z
- 近 30 天下载量：1877989（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：638（近 12 个月 158 个）

## 中文简介

用于与 Descope 集成的节点.js 库

## 安装

```sh
npm install @descope/node-sdk
```

也可以使用：`pnpm add @descope/node-sdk`、`yarn add @descope/node-sdk`、`bun add @descope/node-sdk`

## README

# 节点的SDK望远镜

用于节点.js的 Descope SDK 为 Descope 用户管理和认证 API 提供方便访问 用于以 Node.js 写的后端。 你可以读更多关于 [望远镜网站](https://descope.com/)。 。 。 .

## 所需资源

SDK支持节点版本18及以上.

SDK使用运行时间的原生 `fetch` 而不是节点 HTTP 客户端,所以它也运行在 Cloudflare工人和其他边缘运行时间(工人要求 `nodejs_compat` 旗帜为 `crypto`编号 :`Buffer`) (中文(简体) ).

## 安装 SDK

以 :

```bash
npm i --save @descope/node-sdk
```

## 认证函数

### 设置

在使用下列认证功能之前,必须初始化 `descopeClient` 以使用所有内置的 SDK 函数.

你需要你的望远镜 `Project ID` 来创建它,你可以在 [项目页面](https://app.descope.com/settings/project) 在望远镜控制台.

```typescript
import DescopeClient from '@descope/node-sdk';

const descopeClient = DescopeClient({ projectId: 'my-project-ID' });
```

一旦你创造了一个 `descopeClient`,您可以使用此功能来工作以下功能:

1.  [检察官办公室认证](https://npmcn.com/package/%40descope/node-sdk/#readme-otp-authentication)
2.  [魔法链接](https://npmcn.com/package/%40descope/node-sdk/#readme-magic-link)
3.  [智能链接](https://npmcn.com/package/%40descope/node-sdk/#readme-enchanted-link)
4.  [奥奥特](https://npmcn.com/package/%40descope/node-sdk/#readme-oauth)
5.  [证监会/证监会](https://npmcn.com/package/%40descope/node-sdk/#readme-ssosaml)
6.  [TOTP 认证](https://npmcn.com/package/%40descope/node-sdk/#readme-totp-authentication)
7.  [密码](https://npmcn.com/package/%40descope/node-sdk/#readme-passwords)
8.  [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)
9.  [任务授权验证( L)](https://npmcn.com/package/%40descope/node-sdk/#readme-roles--permission-validation)
10.  [注销](https://npmcn.com/package/%40descope/node-sdk/#readme-logging-out)

## 管理职能

### 设置

在使用下列管理函数之前,必须初始化 `descopeClient`。 。 。 .

如果您也想要使用管理功能, 您需要初始化您的新版本 `descopeClient`但这次是 `ManagementKey` 还有你 `Project ID`中创建管理密钥 [望远镜控制台](https://app.descope.com/settings/company/managementkeys)。 。 。 .

```typescript
import DescopeClient from '@descope/node-sdk';

const descopeClient = DescopeClient({
  projectId: 'my-project-ID',
  managementKey: 'management-key',
});
```

然后,您可以用它来完成以下功能:

1.  [管理租户](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-tenants)
2.  [管理家庭](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-families)
3.  [管理用户](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-users)
4.  [管理访问密钥](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-access-keys)
5.  [管理 SSO 设置](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-sso-setting)
6.  [管理权限](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-permissions)
7.  [管理角色](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-roles)
8.  [查询 SSO 组](https://npmcn.com/package/%40descope/node-sdk/#readme-query-sso-groups)
9.  [管理流程](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-flows)
10.  [管理 JWTs](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-jwts)
11.  [冒名顶替](https://npmcn.com/package/%40descope/node-sdk/#readme-impersonate)
12.  [嵌入式链接](https://npmcn.com/package/%40descope/node-sdk/#readme-embedded-links)
13.  [审计](https://npmcn.com/package/%40descope/node-sdk/#readme-audit)
14.  [管理 FGA( 精细授权)](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-fga-fine-grained-authorization)
15.  [管理工程](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-project)
16.  [管理 SSO 应用程序](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-sso-applications)
17.  [管理密钥](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-management-keys)
18.  [管理探测器](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-descopers)
19.  [管理引擎](https://npmcn.com/package/%40descope/node-sdk/#readme-manage-engines)

如果你想运行我们的任何代码样本 并玩它们,检查我们 [代码示例](https://npmcn.com/package/%40descope/node-sdk/#readme-code-examples) 节.

如果你正在进行端到端测试, 请检查 [用于结束(e2e)测试和整合测试的 Utils](https://npmcn.com/package/%40descope/node-sdk/#readme-utils-for-your-end-to-end-e2e-tests-and-integration-tests) 节。 您需要使用 `descopeClient` 您创建于 [管理职能](https://npmcn.com/package/%40descope/node-sdk/#readme-management-functions)。 。 。 .

## 认证管理密钥

这个 `authManagementKey` 是一种替代 `managementKey` 提供一种在保持认证客户与管理客户分离的同时开展管理业务的方法.

### 密钥差异

-   **目的**: 使用 `authManagementKey` 与认证有关的管理业务,同时 `managementKey` 用于一般管理业务
-   **客户离职**: 您可以有一个客户端用于管理操作, 另一个用于认证操作
-   **相互排斥**: 您不能通过两者 `authManagementKey` 财务报告和审定财务报表 `managementKey` 一起 - 根据您的使用大小写选择一个

### 用法实例

**使用认证管理键进行认证操作 :**

```typescript
import DescopeClient from '@descope/node-sdk';

const authClient = DescopeClient({
  projectId: 'my-project-ID',
  authManagementKey: 'auth-management-key',
});

// This client can be used for authentication-related management operations
```

**不同操作的单独客户端 :**

```typescript
import DescopeClient from '@descope/node-sdk';

// Client for general management operations
const managementClient = DescopeClient({
  projectId: 'my-project-ID',
  managementKey: 'management-key',
});

// Client for authentication operations
const authClient = DescopeClient({
  projectId: 'my-project-ID',
  authManagementKey: 'auth-management-key',
});

// Use managementClient for user management, tenant management, etc.
// Use authClient for authentication-related operations
```

**说明**: 在 [望远镜控制台](https://app.descope.com/settings/company/managementkeys),类似于您创建常规管理密钥的方式.

* * *

## 处理错误

每个 `async` 操作可能失败。 如果确实如此,将掌握有关反应对象发生的情况. 一个典型的错误处理案例可能看起来类似:

```ts
import DescopeClient, { SdkResponse } from '@descope/node-sdk';

const { DescopeErrors } = DescopeClient;

// ...

try {
  const resp = await sdk.otp.signIn.email(loginId);
  if (resp.error) {
    switch (resp.error.errorCode) {
      case DescopeErrors.userNotFound:
        // Handle specifically
        break;
      default:
      // Handle generally
      // `resp.error` will contain `errorCode`, `errorDescription` and sometimes `errorMessage` to
      // help understand what went wrong. See SdkResponse for more information.
    }
  }
} catch (e) {
  // Handle technical error
}
```

* * *

### 检察官办公室认证

使用您喜欢的送出方法向用户发送一次性密码( OTP ) (_电子邮件/短信/语音呼叫/WhatsApp_) (中文(简体) ). 因此必须提供电子邮件地址或电话号码.

用户也可以 `sign up`, (中文(简体) ), `sign in` 或者说 `sign up or in`

```typescript
// Every user must have a login ID. All other user information is optional
const loginId = 'desmond@descope.com';
const user = {
  name: 'Desmond Copland',
  phone: '212-555-1234',
  email: loginId,
};
await descopeClient.otp.signUp['email'](loginId, user);
```

用户将使用所选的传送方法接收一个代码. 使用 :

```typescript
const jwtResponse = await descopeClient.otp.verify['email'](loginId, 'code');
// jwtResponse.data.sessionJwt
// jwtResponse.data.refreshJwt
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

### 魔法链接

使用您首选的送出方法发送一个用户的魔法链接( S)_电子邮件/短消息_) (中文(简体) ). "魔法链接"会将用户重定向到需要校验其符号的页面. 这种重定向可以在代码中配置,也可以在全球范围配置 [望远镜控制台](https://app.descope.com/settings/authentication/magiclink)

用户也可以 `sign up`, (中文(简体) ), `sign in` 或者说 `sign up or in`

```typescript
// If configured globally, the redirect URI is optional. If provided however, it will be used
// instead of any global configuration
const URI = 'http://myapp.com/verify-magic-link';
await descopeClient.magicLink.signUpOrIn['email']('desmond@descope.com', URI);
```

要校验一个魔法链接, 您的重定向页面必须调用符号上的验证功能 (`t`)参数(`https://your-redirect-address.com/verify?t=<token>`:

```typescript
const jwtResponse = await descopeClient.magicLink.verify('token');
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

### 智能链接

使用 Cnitched Link API 可使用户通过点击链接签名 他们的电子邮件地址。 电子邮件将包括三个不同的链接, 而用户必须点击正确的一个, 以 2 位数字为基础 在启动认证进程时显示.

这种方法类似于 [魔法链接](https://npmcn.com/package/%40descope/node-sdk/#readme-magic-link) 但主要有两种不同:

-   用户必须从三个中选择正确的链接, 而不是只有一个 单链接.
-   这支持交叉设备点击,意味着用户可以尝试在一个设备上登录, 类似计算机,同时点击另一个设备的链接,例如移动电话.

Chanted Link 将把用户重新定向到需要校验其符号的页面 . 这种重定向可以按照请求的代码配置,也可以在全球设置 [望远镜控制台](https://app.descope.com/settings/authentication/enchantedlink)。 。 。 .

用户也可以 `sign up`, (中文(简体) ), `sign in` 或者说 `sign up or in`

```typescript
// If configured globally, the redirect URI is optional. If provided however, it will be used
// instead of any global configuration.
const URI = 'http://myapp.com/verify-enchanted-link';
const enchantedLinkRes = await descopeClient.enchantedLink.signIn('desmond@descope.com', URI);
enchantedLinkRes.data.linkId; // Should be displayed to the user so they can click the corresponding link in the email
enchantedLinkRes.data.pendingRef; // Used to poll for a valid session
```

发送链接后,您必须使用 `pendingRef` 从 上一个步骤。 只有在用户点击正确的链接后才会返回有效的会话 .

```typescript
// Poll for a certain number of tries / time frame. You can control the polling interval and time frame
// with the optional WaitForSessionConfig
const jwtResponse = await descopeClient.enchantedLink.waitForSession(
  enchantedLinkRes.data.pendingRef,
);
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

要验证一个被魔法化的链接, 您的重定向页面必须调用符号上的验证函数( Q)`t`)参数(`https://your-redirect-address.com/verify?t=<token>`) (中文(简体) ). 一旦该标志得到核实,会议投票将获得有效答复.

```typescript
try {
  await descopeClient.enchantedLink.verify('token');
  // token is invalid
} catch (error) {
  // token is valid
}
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

### 奥奥特

用户可以通过OAuth协议,使用他们的社交登录进行认证. 配置您的 OAuth 设置 [望远镜控制台](https://app.descope.com/settings/authentication/social)。要启动 OAuth 流量呼叫:

```typescript
// Choose an oauth provider out of the supported providers
// If configured globally, the return URL is optional. If provided however, it will be used
// instead of any global configuration.

const urlRes = await descopeClient.oauth.start['google'](redirectUrl);
urlRes.data.url; // Redirect the user to the returned URL to start the OAuth redirect chain
```

用户将使用认证提供者进行认证,并将重定向回重定向的 URL,并附有一个附件 `code` HTTP URL 参数. 用它来验证用户:

```typescript
const jwtResponse = await descopeClient.oauth.exchange('token');
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

### 证监会/证监会

用户可以使用 SAML 或 Single Sign On 认证给特定租户。 配置您的 SSO/ SAML 设置 [望远镜控制台](https://app.descope.com/settings/authentication/sso)。要启动一个流量呼叫:

```typescript
// If configured globally, the return URL is optional. If provided however, it will be used
// instead of any global configuration.
const redirectUrl = 'https://my-app.com/handle-saml';
const urlRes = await descopeClient.saml.start('tenant'); // Choose which tenant to log into. An email can also be provided here and the domain will be extracted from it
urlRes.data.url; // Redirect the user to the given returned URL to start the SSO/SAML redirect chain
```

用户将使用为租户配置的认证提供者进行认证,并将重新定向到重新定向的 URL,并附有一个附件 `code` HTTP URL 参数. 用它来验证用户:

```typescript
const jwtResponse = await descopeClient.saml.exchange('token');
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

### TOTP 认证

用户可以使用Google认证程序等认证程序进行认证. 签字就像你用其他认证方法一样 签到的回复 然后将包含一个 QR 代码 `image` 可以显示给用户以便使用 或用户可以输入 `key` 手动或单击 提供的联系 `provisioningURL`。 。 。 .

现有用户可以使用 `update` 函数.

```typescript
// Every user must have a login ID. All other user information is optional
const loginId = 'desmond@descope.com';
const user = {
  name: 'Desmond Copland',
  phone: '212-555-1234',
  email: loginId,
};
const totpRes = await descopeClient.totp.signUp(loginId, user);
// Use one of the provided options to have the user add their credentials to the authenticator
totpRes.data.provisioningURL;
totpRes.data.image;
totpRes.data.key;
```

有三种不同的方式允许用户在 它们的认证程序 - 要么点击提供 URL, 扫描 QR 图像或手动插入密钥。 之后,使用代码签名 应用程序生产.

```typescript
const jwtResponse = await descopeClient.totp.verify(loginId, 'code');
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

#### 删除 TOTP 种子

提供 `loginId` 到删除用户 TOTP 种子的函数.

```typescript
const response = await descopeClient.management.user.removeTOTPSeed(loginId);
```

#### 删除回收代码

为功能提供登录ID或用户ID来删除用户的所有恢复代码.

```typescript
const response = await descopeClient.management.user.removeRecoveryCodes(loginIdOrUserId);
```

### 密码

用户也可以使用密码进行认证,不过建议 如果可能,更倾向于无密码认证方法。 签名需要 调用以提供符合所有配置要求的有效密码 联 合 国 [密码认证方法](https://app.descope.com/settings/authentication/password) 在望远镜控制台.

```js
// Every user must have a loginId. All other user information is optional
const loginId = 'desmond@descope.com';
const password = 'qYlvi65KaX';
const user = {
  name: 'Desmond Copeland',
  email: loginId,
};
const jwtResponse = await descopeClient.password.signUp(loginId, password, user);
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

用户以后可以使用相同的登录ID和密码签名.

```js
const jwtResponse = await descopeClient.password.signIn(loginId, password);
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

届会和刷新JWT应交回致电者,并在会中与每一项请求相通。 更多信息 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation)

如果用户需要更新密码,有两种方法之一: 重置密码或替换密码

**更改密码**

_注意: 发送重置只有在用户有有效的电子邮件地址时才会工作 。 否则密码重设提示无法发送 ._

在那个 [密码认证方法](https://app.descope.com/settings/authentication/password) 在Descope控制台中,可以定义可以使用哪种替代认证方法来认证用户,以重置并更新他们的密码.

```js
// Start the reset process by sending a password reset prompt. In this example we'll assume
// that magic link is configured as the reset method. The optional redirect URL is used in the
// same way as in regular magic link authentication.
const loginId = 'desmond@descope.com';
const redirectURL = 'https://myapp.com/password-reset';
const passwordResetResponse = await descopeClient.password.sendReset(loginId, redirectURL);
```

在此情况下,必须像其他任何魔法链接一样核实魔法链接(见 [魔法链接部分](https://npmcn.com/package/%40descope/node-sdk/#readme-magic-link) 详情请查阅。 不过,在核实用户后,预期 允许他们提供新的密码,而不是旧密码。 由于用户现已获得认证,因此可以通过下列方式:

```js
// The refresh token is required to make sure the user is authenticated.
await descopeClient.password.update(loginId, newPassword, token);
```

`update()` 当用户被认证并具有有效的会话时,总是可以调用.

或者,也可以用新的密码取代现有的有效密码.

```js
// Replaces the user's current password with a new one
const jwtResponse = await descopeClient.password.replace(loginId, oldPassword, newPassword);
// jwtResponse.data.sessionJwt;
// jwtResponse.data.refreshJwt;
```

### 会话验证

您的客户端和服务器之间进行的每一个安全请求都需要验证 。 客户端发送 并使用下列方法之一加以验证:

```typescript
// Validate the session. Will throw if expired
const authInfo = await descopeClient.validateSession('sessionToken');

// If validateSession throws an exception, you will need to refresh the session using
const refreshed = await descopeClient.refreshSession('refreshToken');

// Alternatively, you could combine the two and
// have the session validated and automatically refreshed when expired
const combined = await descopeClient.validateAndRefreshSession('sessionToken', 'refreshToken');

// Optional: Validate audience  for backend-only flows
// Provide VerifyOptions with the expected audience(s)
const withAud = await descopeClient.validateSession('sessionToken', { audience: 'my-audience' });
const withAudArray = await descopeClient.validateSession('sessionToken', { audience: ['a', 'b'] });

// Audience is enforced for session JWTs only (including after refresh)
const refreshedWithAud = await descopeClient.refreshSession('refreshToken', { audience: 'api' });
const combinedWithAud = await descopeClient.validateAndRefreshSession(
  'sessionToken',
  'refreshToken',
  { audience: 'api' },
);
```

对于访问密钥,您也可以针对一个受众验证返回的会话:

```typescript
const authInfo = await descopeClient.exchangeAccessKey('access_key', undefined, {
  audience: 'api',
});
```

选择适合您需要的会话验证和刷新组合 . 刷新会话返回与用户首次登录/登录时返回的相同响应, 载有会话和刷新符号以及所有JWT索赔. 如果直接验证了会话符号, 请将响应中的会话符号返回客户端 .

通常,会通过HTTP头或克克来来来去来来来来来去来来来来来来去去去去去去去. 可根据您的执行情况推迟执行。 看我们的 [实例](https://npmcn.com/package/%40descope/node-sdk/#readme-code-examples) 为了几个例子.

如果使用角色和权限, 在验证会话后立即验证它们 。 见 [下一节](https://npmcn.com/package/%40descope/node-sdk/#readme-roles--permission-validation) 更多信息.

注意: 如果在 Descope 中启用了刷新符号旋转 - `refreshSession` 编号 : `validateAndRefreshSession` 将返回一个新的更新的代号,旧的将失效.

#### DPoP 发件人-约束托肯斯(RFC 9449)

当会话符号为 DPOP 时( 有 `cnf.jkt` 将请求的 DPOP 细节传递给 `validateSession` 或者说 `validateAndRefreshSession`当 `dpop` 选项,缺少或 无效证据被拒绝 。 没有它,一个 DPop 标记记录一个警告并被接受;下一个 主要版本将拒绝。 不受约束的符号不受影响. `validateAndRefreshSession` 刷新后检查证据,所以被拒绝的证据不会撤销 刷新符号旋转 .

```typescript
const [authorizationScheme, sessionToken] = (req.headers.authorization ?? '').split(' ');

const authInfo = await descopeClient.validateSession(sessionToken, {
  dpop: {
    proof: req.headers['dpop'] as string | undefined, // value of the DPoP header
    method: req.method,
    url: `${req.protocol}://${req.get('host')}${req.path}`, // must match the proof's htu
    authorizationScheme, // "Bearer" or "DPoP"
  },
});
```

> **代理服务器后面 :** `url` 必须与证据相符 `htu` (计相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相 节点J可能会看到 `http` 当客户端使用时 `https`快捷键 `trust proxy` 或者自己重建URL.

> **重放保护 :** 证明: `jti` 被同一 SDK 案例在最后 120秒被拒绝. 该商店为内存( 最多10万个条目, 新证据被拒绝) ),所以没有检测到服务器实例之间的重放.

#### 使用中间软件进行会话验证

或者,您可以创建一个简单的中间软件功能,在内部使用 `validateSession` 函数. 此中间软件将自动从请求中解析饼干 . 如果失败,它将以 `401 Unauthorized`。 。 。 .

```typescript
const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const cookies = parseCookies(req);
    const out = await clientAuth.auth.validateSession(
      cookies[DescopeClient.SessionTokenCookieName],
      cookies[DescopeClient.RefreshTokenCookieName],
    );
    if (out?.cookies) {
      res.set('Set-Cookie', out.cookies);
    }
    next();
  } catch (e) {
    res.status(401).json({
      error: 'Unauthorized!',
    });
  }
};
```

### 任务授权验证( L)

在使用角色权限时,必须验证用户是否具备所需的权限( L) 在确保会话有效后立即授权。 采取 `AuthenticationInfo` 收到的文件 [会话验证](https://npmcn.com/package/%40descope/node-sdk/#readme-session-validation),调用以下函数:

用于多种用途:

```typescript
// You can validate specific permissions
const validTenantPermissions = descopeClient.validateTenantPermissions(authInfo, 'my-tenant-ID', [
  'Permission to validate',
]);
if (!validTenantPermissions) {
  // Deny access
}

// Or validate roles directly
const validTenantRoles = descopeClient.validateTenantRoles(authInfo, 'my-tenant-ID', [
  'Role to validate',
]);
if (!validTenantRoles) {
  // Deny access
}

// Or get the matched roles/permissions
const matchedTenantRoles = descopeClient.getMatchedTenantRoles(authInfo, 'my-tenant-ID', [
  'Role to validate',
  'Another role to validate',
]);

const matchedTenantPermissions = descopeClient.getMatchedTenantPermissions(
  authInfo,
  'my-tenant-ID',
  ['Permission to validate', 'Another permission to validate'],
);
```

不使用租户时:

```typescript
// You can validate specific permissions
const validPermissions = descopeClient.validatePermissions(authInfo, ['Permission to validate']);
if (!validPermissions) {
  // Deny access
}

// Or validate roles directly
const validRoles = descopeClient.validateRoles(authInfo, ['Role to validate']);
if (!validRoles) {
  // Deny access
}

// Or get the matched roles/permissions
const matchedRoles = descopeClient.getMatchedRoles(authInfo, [
  'Role to validate',
  'Another role to validate',
]);

const matchedPermissions = descopeClient.getMatchedPermissions(authInfo, [
  'Permission to validate',
  'Another permission to validate',
]);
```

### 注销

您可以通过提供用户 `refreshToken` 参加那届会议. 调用此函数后, 您必须取消或删除您创建的任何 cookie .

```typescript
await descopeClient.logout(refreshToken);
```

也可以从目前所签入的所有设备中签出用户. 通话 `logoutAll` 将 无效所有用户的刷新符号 。 调用此函数后, 您必须取消或删除您创建的任何 cookie .

```typescript
await descopeClient.logoutAll(refreshToken);
```

## 管理职能

通常需要某种形式的管理或自动化。 这些可以执行 使用管理职能。 请注意,这些行动比较敏感,因为它们是行政性的 在自然界中,我们发现 请使用负责任的.

### 设置

要使用管理API,你需要一个 `Management Key` 与你的 `Project ID`。 。 。 . 在 [望远镜控制台](https://app.descope.com/settings/company/managementkeys)。 。 。 .

```typescript
import DescopeClient from '@descope/node-sdk';

const descopeClient = DescopeClient({
  projectId: 'my-project-ID',
  managementKey: 'management-key',
});
```

### 管理租户

您可以创建、更新、删除或加载租户,以及读取和更新租户设置:

```typescript
// The self provisioning domains or optional. If given they'll be used to associate
// Users logging in to this tenant
await descopeClient.management.tenant.create('My Tenant', ['domain.com'], {
  customAttributeName: 'val',
});

// You can optionally set your own ID when creating a tenant
await descopeClient.management.tenant.createWithId('my-custom-id', 'My Tenant', ['domain.com'], {
  customAttributeName: 'val',
});

// Update will override all fields as is. Use carefully.
await descopeClient.management.tenant.update(
  'my-custom-id',
  'My Tenant',
  ['domain.com', 'another-domain.com'],
  { customAttributeName: 'val' },
);

// Unlike update, patchTenant only changes the fields you provide - everything else
// (domains, customAttributes, enforceSSO, ...) is left untouched.
await descopeClient.management.tenant.patchTenant('my-custom-id', {
  name: 'My Tenant',
  disabled: true,
});

// Update the tenant's default roles by providing role names.
// These are project-level roles that will be automatically assigned to users in this tenant.
await descopeClient.management.tenant.updateDefaultRoles('my-custom-id', ['role1', 'role2']);

// Tenant deletion cannot be undone. Use carefully.
// Pass true to cascade value, in case you want to delete all users/keys associated only with this tenant
await descopeClient.management.tenant.delete('my-custom-id', false);

// Load tenant by id
const tenant = await descopeClient.management.tenant.load('my-custom-id');

// Load all tenants
const tenantsRes = await descopeClient.management.tenant.loadAll();
tenantsRes.data.forEach((tenant) => {
  // do something
});

// Search all tenants according to various parameters
const searchRes = await descopeClient.management.tenant.searchAll(['id']);
searchRes.data.forEach((tenant) => {
  // do something
});

// Load tenant settings by id
const tenantSettings = await descopeClient.management.tenant.getSettings('my-tenant-id');

// Update will override all fields as is. Use carefully.
await descopeClient.management.tenant.configureSettings('my-tenant-id', {
  domains: ['domain1.com'],
  selfProvisioningDomains: ['domain1.com'],
  enabled: true,
  refreshTokenExpiration: 12,
  refreshTokenExpirationUnit: 'days',
  sessionTokenExpiration: 10,
  sessionTokenExpirationUnit: 'minutes',
  enableInactivity: true,
  JITDisabled: false,
  inactivityTime: 10,
  inactivityTimeUnit: 'minutes',
});

// Generate tenant admin self service link for SSO Suite (valid for 24 hours)
// ssoId can be provided for a specific sso configuration
// email can be provided to send the link to (email's templateId can be provided as well)
const res = await descopeClient.management.tenant.generateSSOConfigurationLink(
  'my-tenant-id',
  60 * 60 * 24,
);
console.log(res.adminSSOConfigurationLink);

// Optionally set an actor id, recorded as the audit actor for actions taken inside the SSO
// Suite (instead of the temporary user). It is used as-is for audit attribution and is not validated.
const resWithActor = await descopeClient.management.tenant.generateSSOConfigurationLink(
  'my-tenant-id',
  60 * 60 * 24,
  undefined, // ssoId
  undefined, // email
  undefined, // templateId
  'my-admin-actor-id', // actorId
);
console.log(resWithActor.adminSSOConfigurationLink);
```

### 管理家庭

您可以创建、更新、删除或搜索家庭,管理与其链接的用户,以及 冒充家庭依赖者(一个没有自己登录证书的影子用户):

```typescript
// Create a family. The family ID is generated automatically.
const family = await descopeClient.management.family.create('My Family', {
  customAttributeName: 'val',
});

// Create a family with a caller-supplied ID.
await descopeClient.management.family.createWithId('my-family-id', 'My Other Family');

// Update will override all provided fields as is. Omitted fields are left unchanged.
// customAttributes replaces all of the family's custom attributes, it is not merged.
await descopeClient.management.family.update(family.data.id, 'My Family', {
  customAttributeName: 'val2',
});

// Family deletion cannot be undone. Use carefully.
await descopeClient.management.family.delete(family.data.id);

// Search families according to various parameters. Called with no options, returns all families.
const searchRes = await descopeClient.management.family.searchAll({ text: 'My Family' });
searchRes.data.forEach((f) => {
  // do something
});

// Create a dependent (shadow profile) user in a family - a user with no login credentials of
// their own. When loginId is omitted it is derived from name; email/phone are never used as the
// login ID since they are not unique - a dependent may share them with their guardian.
const dependent = await descopeClient.management.family.createDependent(family.data.id, {
  name: 'My Dependent',
});

// Dependent deletion cannot be undone. The family is inferred from the dependent. Regular
// (non-dependent) family members are removed via user.removeFamilies, not deleted.
await descopeClient.management.family.deleteDependent(dependent.data.userId);

// Add a user to one or more families. Each entry may also set the user's roles and family-scoped
// attributes for that family in the same call; omitting roleNames or familyScopedAttributes on a
// family the user already belongs to leaves them unchanged.
await descopeClient.management.user.addFamilies('user-login-id', [
  { familyId: family.data.id, roleNames: ['role1'] },
]);

// Remove a user from one or more families.
await descopeClient.management.user.removeFamilies('user-login-id', [family.data.id]);

// Impersonate a family dependent. The impersonator (by user ID or login ID) must be a member of
// the dependent's family and hold the family impersonate-dependents permission there.
const impersonateRes = await descopeClient.management.family.impersonateDependent(
  'admin-user-id',
  'dependent-login-id',
  family.data.id, // optional - scopes the impersonated session to this family
);
console.log(impersonateRes.data.jwt);

// Stop impersonating a family dependent and return to the acting admin's own session.
const stopRes = await descopeClient.management.family.stopImpersonation(impersonateRes.data.jwt);
console.log(stopRes.data.jwt);

// Get and configure the project's family account settings. Omitted fields are left unchanged.
const settings = await descopeClient.management.family.getSettings();
await descopeClient.management.family.configureSettings({
  enabled: true,
  maxFamilyMembers: 5,
  allowMultipleFamiliesUsers: false,
});

// Manage custom attribute definitions on the family entity itself.
await descopeClient.management.family.createCustomAttributes([{ name: 'plan', type: 1 }]);
const familyAttrs = await descopeClient.management.family.getCustomAttributes();
await descopeClient.management.family.deleteCustomAttributes(['plan']);

// Manage family-scoped user custom attribute definitions - user attributes whose values are held
// per family membership (AssociatedFamily.familyScopedAttributes) rather than on the user.
await descopeClient.management.user.createFamilyScopedCustomAttributes([
  { name: 'nickname', type: 1 },
]);
const familyScopedAttrs = await descopeClient.management.user.getFamilyScopedCustomAttributes();
await descopeClient.management.user.deleteFamilyScopedCustomAttributes(['nickname']);
```

### 管理密码

您可以读取和更新任何租户密码设置和政策 :

```typescript
// Load tenant password settings by id
const passwordSettings = await descopeClient.management.password.getSettings('my-tenant-id');

// Update will override all fields as is. Use carefully.
await descopeClient.management.password.configureSettings('my-tenant-id', {
  enabled: true,
  minLength: 8,
  expiration: true,
  expirationWeeks: 4,
  lock: true,
  lockAttempts: 5,
  reuse: true,
  reuseAmount: 6,
  lowercase: true,
  uppercase: false,
  number: true,
  nonAlphaNumeric: false,
});
```

### 管理 SSO 应用程序

您可以创建、更新、删除或装入 SSO 应用程序:

```typescript
// Create OIDC SSO application
await descopeClient.management.ssoApplication.createOidcApplication({
  name: 'My OIDC app name',
  loginPageUrl: 'http://dummy.com/login',
  clientType: 'confidential', // 'confidential' or 'public'; if omitted, the account's default is used (see oidcSettings.clientType on load)
  // Optional: send the app's back-channel logout URL a logout token when the user is force logged out
  backChannelLogoutUrl: 'https://dummy.com/backchannel-logout',
  notifyOnForceLogout: true,
});

// Create SAML SSO application
await descopeClient.management.ssoApplication.createSamlApplication({
  name: 'My SAML app name',
  loginPageUrl: 'http://dummy.com/login',
  useMetadataInfo: true,
  metadataUrl: 'http://dummy.com/metadata',
  // Optional SAML Single Logout (SLO): the service provider can log the user out with a signed
  // LogoutRequest, and it is sent one when a logout reaches the user's applications
  singleLogoutEnabled: true,
  singleLogoutPropagation: 'allApps', // 'none' (default) or 'allApps'
  singleLogoutScope: 'session', // 'session' or 'allSessions'
  notifyOnForceLogout: true, // also send it a LogoutRequest on a force logout (requires the 'soap' binding)
});

// Create WS-Fed SSO application
await descopeClient.management.ssoApplication.createWsFedApplication({
  name: 'My WS-Fed app name',
  loginPageUrl: 'http://dummy.com/login',
  realm: 'urn:myapp:realm',
  replyUrl: 'http://dummy.com/reply',
});

// Update OIDC SSO application.
// Update will override all fields as is. Use carefully.
await descopeClient.management.ssoApplication.updateOidcApplication({
  id: 'my-app-id',
  name: 'My OIDC app name',
  loginPageUrl: 'http://dummy.com/login',
  clientType: 'confidential', // pass the app's current client type
  backChannelLogoutUrl: 'https://dummy.com/backchannel-logout', // an update without it clears it
});

// Update SAML SSO application.
// Update will override all fields as is. Use carefully.
await descopeClient.management.ssoApplication.updateSamlApplication({
  id: 'my-app-id',
  name: 'My SAML app name',
  loginPageUrl: 'http://dummy.com/login',
  enabled: true,
  useMetadataInfo: false,
  entityId: 'entity1234',
  aceUrl: 'http://dummy.com/acs',
  certificate: 'certificate',
});

// Update WS-Fed SSO application.
// Update will override all fields as is. Use carefully.
await descopeClient.management.ssoApplication.updateWsFedApplication({
  id: 'my-app-id',
  name: 'My WS-Fed app name',
  loginPageUrl: 'http://dummy.com/login',
  enabled: true,
  realm: 'urn:myapp:realm',
  replyUrl: 'http://dummy.com/reply',
});

// SSO application deletion cannot be undone. Use carefully.
await descopeClient.management.ssoApplication.delete('my-app-id');

// Load SSO application by id
const app = await descopeClient.management.ssoApplication.load('my-app-id');

// Load all SSO applications
const appsRes = await descopeClient.management.ssoApplication.loadAll();
appsRes.data.forEach((app) => {
  // do something
});
```

### 管理用户

您可以创建、更新、删除或加载用户,以及按照过滤器进行搜索:

```typescript
// A user must have a login ID, other fields are optional.
// Roles should be set directly if no tenants exist, otherwise set
// on a per-tenant basis.
await descopeClient.management.user.create('desmond@descope.com', {
  email: 'desmond@descope.com',
  displayName: 'Desmond Copeland',
  userTenants: [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
});

// Alternatively, a user can be created and invited via an email / text message.
// Make sure to configure the invite URL in the Descope console prior to using this function,
// and that an email address / phone number is provided in the information.
await descopeClient.management.user.invite('desmond@descope.com', {
  email: 'desmond@descope.com',
  displayName: 'Desmond Copeland',
  userTenants: [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
  // You can override the project's User Invitation Redirect URL with this parameter
  inviteUrl: '<invite-url>',
  // You can inject custom data into the template.
  // Note that you first need to configure custom template in Descope Console
  // For example: configure {{options_k1}} in the custom template, and pass { k1: 'v1' } as templateOptions
  templateOptions: { k1: 'v1', k2: 'v2' },
});

// You can invite batch of users via an email / text message.
// Make sure to configure the invite URL in the Descope console prior to using this function,
// and that an email address / phone number is provided in the information. You can also set
// a cleartext password or import a prehashed one from another service.
// Note: This function will send an invitation to each user in the `users` array. If you want to create users without sending invitations, use `createBatch` instead.
await descopeClient.management.user.inviteBatch(
  [
    {
      loginId: 'desmond@descope.com',
      email: 'desmond@descope.com',
      phone: '+123456789123',
      displayName: 'Desmond Copeland',
      userTenants: [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
      hashedPassword: {
        bcrypt: {
          hash: '$2a$...',
        },
      },
    },
  ],
  '<invite_url>',
  true,
  false,
);

// Create a batch of users.
// This is useful when you want to create users programmatically without triggering the invitation flow.
// You can set a cleartext password or import a prehashed one from another service.
// Note: This function will NOT send an invitation to the created users. If invitations are required use `inviteBatch` instead.
await descopeClient.management.user.createBatch([
  {
    loginId: 'desmond@descope.com',
    email: 'desmond@descope.com',
    phone: '+123456789123',
    displayName: 'Desmond Copeland',
    userTenants: [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
    hashedPassword: {
      bcrypt: {
        hash: '$2a$...',
      },
    },
  },
]);

// Update will override all fields as is, including family memberships: omitting
// familyAssociations removes the user from all of their families, and updating a dependent
// requires familyAssociations with the dependent's family. Use carefully, or use patch instead.
await descopeClient.management.user.update('desmond@descope.com', {
  email: 'desmond@descope.com',
  displayName: 'Desmond Copeland',
  userTenants: [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
});

// Update explicit data for a user rather than overriding all fields
await descopeClient.management.user.updatePhone('desmond@descope.com', '+18005551234', true);
await descopeClient.management.user.updateLoginId('desmond@descope.com', 'bane@descope.com');
await descopeClient.management.user.removeTenantRoles(
  'desmond@descope.com',
  'tenant-ID1',
  'role-name2',
);

// Update explicit user's data using patch (will override only provided fields)
const options: PatchUserOptions = { displayName: 'Desmond Copeland Jr.' };
await descopeClient.management.user.patch('desmond@descope.com', options);

// User deletion cannot be undone. Use carefully.
await descopeClient.management.user.delete('desmond@descope.com');
// Delete a batch of users. This requires Descope user IDs.
await descopeClient.management.user.deleteBatch(['<user-ID-1>', '<user-ID-2>']);

// Load specific user
const userRes = await descopeClient.management.user.load('desmond@descope.com');

// If needed, users can be loaded using the user ID as well
const userRes = await descopeClient.management.user.loadByUserId('<user-ID>');

// loadUsers - load users by their user id, optionally you can decide if to return invalid users
const usersRes = await descopeClient.management.user.loadUsers(['<user-ID>']);
usersRes.data.forEach((user) => {
  // do something
});

// Search all users, optionally according to tenant and/or role filter
// Results can be paginated using the limit and page parameters
// Additional filters: verifiedEmail, verifiedPhone, statuses, roles, tenantIds, etc.
const usersRes = await descopeClient.management.user.search({
  tenantIds: ['tenant-ID'],
  verifiedEmail: true, // optional: filter by verified email status
  verifiedPhone: false, // optional: filter by verified phone status
});
console.log('Total users:', usersRes.data.total);
usersRes.data.users.forEach((user) => {
  // do something
});

await descopeClient.management.user.logoutUser('my-custom-id');

await descopeClient.management.user.logoutUserByUserId('<user-ID>');

// Logout sessions by creation time. Each matching session is logged out on its next refresh or validation.
// At least one of `before` or `after` is required. `before` defaults to the server's current time; prefer
// omitting it over passing new Date(), since a `before` in the future is rejected. Optionally limit to
// specific session types with `sessionTypes`. The range stays active for a year. Deleting it stops it from
// logging out matching sessions it hasn't logged out yet; sessions already logged out stay logged out.
// The returned range is what the server stored, which may have a later `after` than requested.
// For example, log out sessions created in the last hour:
const rangeRes = await descopeClient.management.user.logoutSessionsCreatedBetween({
  after: new Date(Date.now() - 3600 * 1000),
});
const rangesRes = await descopeClient.management.user.listLogoutSessionRanges();
await descopeClient.management.user.deleteLogoutSessionRange(rangeRes.data.id);

// Get users' authentication history
const userIds = ['user-id-1', 'user-id-2'];
const usersHistoryRes = await descopeClient.management.user.history(userIds);
usersHistoryRes.forEach((userHistory) => {
  // do something
});
```

#### 设置或过期用户密码

您可以为用户设置新的活动密码, 用户可以一起签名 . 您也可以设置一个临时密码, 用户在下次登录时将被迫更改 . 对于已经拥有活性密码的用户,可以过期其当前密码,有效要求他们在下一次登录时更改密码.

```typescript
// Set a user's temporary password
await descopeClient.management.user.setTemporaryPassword('<login-ID>', '<some-password>');

// Set a user's password
await descopeClient.management.user.setActivePassword('<login-ID>', '<some-password>');

// Or alternatively, expire a user password
await descopeClient.management.user.expirePassword('<login-ID>');
```

### 管理工程

您可以更新工程名称和标签, 以及复制当前项目到一个新的项目 :

```typescript
// Update will override all fields as is. Use carefully.
await descopeClient.management.project.updateName('new-project-name');

// Set will override all fields as is. Use carefully.
await descopeClient.management.project.updateTags(['tag1!', 'new']);

// Clone the current project to a new one
// Note that this action is supported only with a pro license or above.
const cloneRes = await descopeClient.management.project.clone('new-project-name');
```

使用公司管理密钥,您可以得到公司所有项目的列表:

```typescript
const projects = await descopeClient.management.project.listProjects();
```

您可以通过导出快照来管理您的项目的设置和配置 :

```typescript
// Exports the current state of the project
const exportRes = await descopeClient.management.project.exportSnapshot();
```

您也可以将先前导出快照导入同一项目或不同的项目 :

```typescript
const validateReq = {
  files: exportRes.data.files,
};

// Validate that an exported snapshot can be imported into the current project
const validateRes = await descopeClient.management.project.import(files);
if (!validateRes.ok) {
  // validation failed, check failures and missingSecrets to fix this
}

// Import the previously exported snapshot into the current project
const importReq = {
  files: exportRes.data.files,
};

await descopeClient.management.project.importSnapshot(files);
```

### 管理访问密钥

您可以创建、更新、删除或加载访问密钥,并根据过滤器进行搜索:

```typescript
// An access key must have a name and expiration, other fields are optional.
// Roles should be set directly if no tenants exist, otherwise set
// on a per-tenant basis.
// If userId is supplied, then authorization will be ignored, and the access key will be bound to the user's authorization.
// If customClaims is supplied, then those claims will be present in the JWT returned by calls to ExchangeAccessKey.
// If description is supplied, then the access key will hold a descriptive text.
// If permittedIps is supplied, then the access key can only be used from that list of IP addresses or CIDR ranges.
await descopeClient.management.accessKey.create(
  'key-name',
  123456789, // expiration time
  null,
  [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
  undefined, // userId
  undefined, // customClaims
  undefined, // description
  undefined, // permittedIps
  { attributeName: 'attributeValue' }, // customAttributes
);

// Load specific user
const accessKeyRes = await descopeClient.management.accessKey.load('key-id');

// Search all users, optionally according to tenant and/or role filter
const accessKeysRes = await descopeClient.management.accessKey.searchAll(['tenant-ID']);
accessKeysRes.data.forEach((accessKey) => {
  // do something
});

// Update will override all fields as is. Use carefully.
await descopeClient.management.accessKey.update('key-id', 'new-key-name', 'new-description');

// Access keys can be deactivated to prevent usage. This can be undone using "activate".
await descopeClient.management.accessKey.deactivate('key-id');

// Disabled access keys can be activated once again.
await descopeClient.management.accessKey.activate('key-id');

// Access key deletion cannot be undone. Use carefully.
await descopeClient.management.accessKey.delete('key-id');
```

### 管理 SSO 设置

您可以管理SSO设置并映射SSO组角色和用户属性.

```typescript
// You can get SSO settings for a specific tenant ID
// You can pass ssoId in case using multi SSO and you want to load specific SSO configuration
const ssoSettings = await descopeClient.management.sso.loadSettings('tenant-id');

// You can get all configured SSO settings for a specific tenant ID (for multi SSO usage)
const allSSOSettings = await descopeClient.management.sso.loadAllSettings('tenant-id');

// You can configure SSO settings manually by setting the required fields directly
// You can pass ssoId in case using multi SSO and you want to configure specific SSO configuration
const tenantId = 'tenant-id'; // Which tenant this configuration is for
const idpUrl = 'https://idp.com';
const entityId = 'my-idp-entity-id';
const idpCert = '<your-cert-here>';
const redirectURL = 'https://my-app.com/handle-sso'; // Global redirect URL for SSO/SAML
const domains = ['tenant-users.com']; // Users authentication with this domain will be logged in to this tenant
await descopeClient.management.sso.configureSAMLSettings(
  tenantID,
  { idpUrl, entityId, idpCert },
  redirectURL,
  domains,
);

// Alternatively, configure using an SSO metadata URL
// You can pass ssoId in case using multi SSO and you want to configure specific SSO configuration
await descopeClient.management.sso.configureSAMLByMetadata(
  tenantID,
  { idpMetadataUrl: 'https://idp.com/my-idp-metadata' },
  redirectURL,
  domains,
);

// Descope signs the SAML AuthnRequest it sends to the IdP. A few IdPs reject a signed request because
// their trusted provider entry holds no signing certificate for Descope - pass disableSignRequest on the
// settings (available on both variants above) to send the request unsigned for that configuration only.
await descopeClient.management.sso.configureSAMLSettings(
  tenantID,
  { idpUrl, entityId, idpCert, disableSignRequest: true },
  redirectURL,
  domains,
);

// A configuration can be classified as authentication only: a login through it verifies the person's
// identity and returns the IdP response, creating no user and issuing no session, so it grants no
// access to your application. Omit authenticationOnly and the stored classification is kept, so an
// ordinary settings edit cannot clear it by omission; pass false to clear it. The same field is on the
// OIDC and Cross-App Access settings, and setting it through any one of them classifies the whole
// configuration. Read it back from the load response's top-level authenticationOnly.
await descopeClient.management.sso.configureSAMLSettings(
  tenantID,
  { idpUrl, entityId, idpCert, authenticationOnly: true },
  redirectURL,
  domains,
);

// JIT provisioning can be turned off per SSO configuration: a login through it then signs in only
// users who already exist (invited, or provisioned through SCIM) and refuses anyone else. It applies to
// the configuration named by ssoId, or to the tenant's default configuration when ssoId is omitted.
// Omit jitDisabled to keep the stored value; pass false to turn JIT back on. The same field is on the
// OIDC settings. Read it back from the load response's top-level jitDisabled.
await descopeClient.management.sso.configureSAMLSettings(
  tenantID,
  { idpUrl, entityId, idpCert, jitDisabled: true },
  redirectURL,
  domains,
  'my-sso-id', // ssoId: omit for the tenant's default SSO configuration
);

// In case SSO is configured to work with OIDC use the following
// You can pass ssoId in case using multi SSO and you want to configure specific SSO configuration
const name = 'some-name';
const clientId = 'client id of OIDC';
const clientSecret = 'client secret';
// usePkce sends a PKCE code challenge to the IdP; omit it to keep the stored value
await descopeClient.management.sso.configureOIDCSettings(
  tenantID,
  { name, clientId, clientSecret, redirectUrl, usePkce: true },
  domains,
);

// You can create new SSO configuration (aka multi SSO)
const ssoId = 'my-new-additional-sso-id';
const displayName = 'My additional SSO configuration';
await descopeClient.management.sso.newSettings(tenantID, ssoId, displayName);

// You can delete existing SSO configuration
// You can pass ssoId in case using multi SSO and you want to delete specific SSO configuration
await descopeClient.management.sso.deleteSettings(tenantID);

// You can disable an SSO configuration without deleting it, and enable it again later.
// Its settings, mappings and domains are kept, so re-enabling needs no payload.
// You can pass ssoId in case using multi SSO and you want to disable a specific SSO configuration
await descopeClient.management.sso.configureAuthType(tenantID, 'none', ssoId);
// Enable it again on the protocol it is configured for ('saml' or 'oidc')
await descopeClient.management.sso.configureAuthType(tenantID, 'saml', ssoId);
```

注:证书的结构应与:

```
-----BEGIN CERTIFICATE-----
Certifcate contents
-----END CERTIFICATE-----
```

/ 您可以删除特定租户标识的 SSO 设置 正在等待 excope.client.management.sso.deleteSettings ("租户-d") 中

### 管理权限

您可以创建、更新、删除或加载权限 :

```typescript
// You can optionally set a description for a permission.
const name = 'My Permission';
let description = 'Optional description to briefly explain what this permission allows.';
await descopeClient.management.permission.create(name, description);

// Update will override all fields as is. Use carefully.
const newName = 'My Updated Permission';
description = 'A revised description';
await descopeClient.management.permission.update(name, newName, description);

// Permission deletion cannot be undone. Use carefully.
await descopeClient.management.permission.delete(newName);

// Load all permissions
const permissionsRes = await descopeClient.management.permission.loadAll();
permissionsRes.data.forEach((permission) => {
  // do something
});
```

### 管理角色

您可以创建、更新、删除或加载角色 :

```typescript
// You can optionally set a description and associated permission for a roles.
// The optional `tenantId` will scope this role for a specific tenant. If left empty, the role will be available to all tenants.
const name = 'My Role';
const tenantId = '<tenant id>';
let description = 'Optional description to briefly explain what this role allows.';
const permissionNames = ['My Updated Permission'];
descopeClient.management.role.create(name, description, permissionNames, tenantId);

// Update will override all fields as is. Use carefully.
const newName = 'My Updated Role';
description = 'A revised description';
permissionNames.push('Another Permission');
descopeClient.management.role.update(name, newName, description, permissionNames, tenantId);

// Role deletion cannot be undone. Use carefully.
descopeClient.management.role.delete(newName, tenantId);

// Load all roles
const rolesRes = await descopeClient.management.role.loadAll();
rolesRes.data.forEach((role) => {
  // do something
});

// Search roles
const rolesRes = await descopeClient.management.role.search({
  tenantIds: ['t1', 't2'],
  roleNames: ['role1'],
});
rolesRes.data.forEach((role) => {
  // do something
});
```

### 查询 SSO 组

您可以查询 SSO 组 :

```typescript
// Load all groups for a given tenant id
const groupsRes = descopeClient.management.group.loadAllGroups('tenant-id');

// Load all groups for the given user IDs (can be found in the user's JWT)
const groupsRes = descopeClient.management.group.loadAllGroupsForMember('tenant-id', [
  'user-id-1',
  'user-id-2',
]);

// Load all groups for the given user login IDs (used for sign-in)
const groupsRes = descopeClient.management.group.loadAllGroupsForMember(
  'tenant-id',
  [],
  ['login-id-1', 'login-id-2'],
);

// Load all group's members by the given group id
const groupsRes = descopeClient.management.group.loadAllGroupMembers('tenant-id', 'group-id');

groupsRes.data.forEach((group) => {
  // do something
});
```

### 管理流程

您可以列出您的流量以及导入和导出流量和屏幕, 或者项目主题 :

```typescript
// List all project flows
const res = await descopeClient.management.flow.list();
console.log('found total flows', res.total);
res.flows.forEach((flowMetadata) => {
  // do something
});

// Delete flows by ids
await descopeClient.management.flow.delete(['flow-1', 'flow-2']);

// Export the flow and it's matching screens based on the given id
const res = await descopeClient.management.flow.export('sign-up');
console.log('found flow', res.data.flow);
res.data.screens.forEach((screen) => {
  // do something
});

// Import the given flow and screens as the given id
const { flow, screens } = res.data;
const updatedRes = descopeClient.management.flow.import('sign-up', flow, screens);
console.log('updated flow', updatedRes.data.flow);
updatedRes.data.screens.forEach((screen) => {
  // do something
});

// Run a management Flow
// Note: Flow must be a management flow, not an interactive flow
const runRes = await descopeClient.management.flow.run('management-flow-id');
console.log('flow result', runRes.data); // The result data will contain the flow's output, which is configured in the 'End' step of the flow

// Run a management Flow with input
// Note: Flow must be a management flow, not an interactive flow
const runWithInputRes = await descopeClient.management.flow.run('management-flow-id', {
  input: {
    key1: 'value1',
  },
});
console.log('flow with input result', runWithInputRes.data); // The result data will contain the flow's output, which is configured in the 'End' step of the flow

// Export the current theme of the project
const res = descopeClient.management.theme.export();
console.log(res.data.theme);

// Import the given theme to the project
const updatedRes = descopeClient.management.theme.import(theme);
console.log(updatedRes.data.theme);
```

### 管理 JWTs

您可以在有效的 JWT 中添加自定义要求 .

```typescript
const updatedJWTRes = await descopeClient.management.jwt.update('original-jwt', {
  customKey1: 'custom-value1',
  customKey2: 'custom-value2',
});
```

为用户生成JWT,在请求中模拟一个符号.

```typescript
const res = await descopeClient.management.jwt.signIn('dummy');
```

为用户生成 JWT, 模拟一个签名请求 .

```typescript
const res = await descopeClient.management.jwt.signUp('dummy');
```

为用户生成JWT,模拟一个签名或请求.

```typescript
const res = await descopeClient.management.jwt.signUpOrIn('dummy');
```

为 OAuth 流量生成客户端断言 JWT .

```typescript
const clientAssertionRes = await descopeClient.management.jwt.generateClientAssertionJwt(
  'https://example.com/issuer', // issuer
  'client-id-123', // subject
  ['https://example.com/token'], // audience
  300, // expiresIn - number of seconds the token will will be valid for
  false, // Optional. flattenAudience - set the audience claim as one string instead of array of strings (for case only one audience value has given)
  'RS256', // Optional. algorithm - set the signing algorithm, value should be one of 'RS256', 'RS384', 'ES384' (default is RS256)
);
// clientAssertionRes.data.jwt contains the client assertion JWT
```

### 冒名顶替

您可以冒充到另一个用户 假冒用户必须拥有 `impersonation` 允许此请求生效. 反应将是冒名顶替用户的JWT的更新

```typescript
const updatedJWTRes = await descopeClient.management.jwt.impersonate(
  'impersonator-id',
  'login-id',
  true,
  { k1: 'v1' },
  't1',
);
```

一旦假扮完成,你可以打电话 `stopImpersonation`,拿回一个jwt ht演员

```typescript
const updatedJWTRes = await descopeClient.management.jwt.impersonate(
  '<jwt string>',
  { k1: 'v1' },
  't1',
);
```

注1:生成代码/链接功能,只为测试用户工作,不会为常规用户工作. 注2:如果在测试用户的登录/注册操作中,需要保证在调用登录/注册操作前生成代码.

### 嵌入式链接

可以创建嵌入式链接,直接接收可核查的符号而无需发送. 然后可以使用魔法链接"验证"的功能直接或通过流来验证这个符号.

```typescript
const { token } = await descopeClient.management.user.generateEmbeddedLink('desmond@descope.com', {
  key1: 'value1',
});
```

### 审计

您可以对各个字段的特定值或全文进行审计搜索。 审计搜索限于过去30天.

```typescript
// Full text search on the last 10 days
const audits = await descopeClient.management.audit.search({
  from: Date.now() - 10 * 24 * 60 * 60 * 1000,
  text: 'some-text',
});
console.log(audits);

// Search successful logins in the last 30 days
const audits = await descopeClient.management.audit.search({ actions: ['LoginSucceed'] });
console.log(audits);
```

您也可以使用数据创建审计事件

```typescript
await descopeClient.management.audit.createEvent({
  action: 'pencil.created',
  type: 'info', // info/warn/error
  actorId: 'UXXX',
  tenantId: 'tenant-id',
  data: {
    some: 'data',
  },
});
```

### 管理 FGA( 精细授权)

Descope支持完全基于关系的访问控制(ReBAC),使用像schema和操作一样的zanzibar. 一个计划由类型(如文档,文件夹,org等实体)组成,每个类型都有关系定义和权限来定义与其他类型的关系.

文件系统的一个简单的例子是:

```yaml
model AuthZ 1.0

type user

type org
  relation member: user
  relation parent: org

type folder
  relation parent: folder
  relation owner: user | org#member
  relation editor: user
  relation viewer: user

  permission can_create: owner | parent.owner
  permission can_edit: editor | can_create
  permission can_view: viewer | can_edit

type doc
  relation parent: folder
  relation owner: user | org#member
  relation editor: user
  relation viewer: user

  permission can_create: owner | parent.owner
  permission can_edit: editor | can_create
  permission can_view: viewer | can_edit
```

SDK扫描仪使您能够充分管理计划与关系,并对关系的存在进行简单(而不是如此简单)的检查.

```typescript
const descopeClient = require('@descope/node-sdk');

// Save schema
await descopeClient.management.fga.saveSchema(schema);

// Create a relation between a resource and user
await descopeClient.management.fga.createRelations([
  {
    resource: 'some-doc',
    resourceType: 'doc',
    relation: 'owner',
    target: 'u1',
    targetType: 'user',
  },
]);

// Check if target has a relevant relation
// The answer should be true because an owner can also view
const relations = await descopeClient.management.fga.check([
  {
    resource: 'some-doc',
    resourceType: 'doc',
    relation: 'can_view',
    target: 'u1',
    targetType: 'user',
  },
]);
```

重复FGA的反应时间 `check` 调用,特别是在高音量情景下,可以通过将调用重定向到与您应用程序相同的后端集群中的Descope FGA Cache Proxy运行来将调用降低到分毫秒分.

在通过Descope设置代理服务器后, 提供了 Docker 图像, 设置 `fgaCacheUrl` 参数与代理 URL 相等,以便在 SDK 中使用,如下例所示:

> **说明:** 两者 `fgaCacheUrl` 财务报告和审定财务报表 `managementKey` 必须规定要使用缓存代理。 如果只是这样的话 `fgaCacheUrl` 配置时没有 `managementKey`,请求将使用标准的Descope API.

```typescript
import DescopeClient from '@descope/node-sdk';

// Initialize client with FGA cache URL
const descopeClient = DescopeClient({
  projectId: '<Project ID>',
  managementKey: '<Management Key>', // Required for cache proxy
  fgaCacheUrl: 'https://10.0.0.4', // example FGA Cache Proxy URL, running inside the same backend cluster
});
```

当 `fgaCacheUrl` 配置, 以下 FGA 方法将自动使用缓存代理, 而不是默认的 Descope API :

-   `saveSchema`
-   `createRelations`
-   `deleteRelations`
-   `check`

如果缓存代理无法到达或返回出错,SDK会自动回落到标准的Descope API.

其他FGA业务如: `loadResourcesDetails` 财务报告和审定财务报表 `saveResourcesDetails` 将继续使用标准的Descope API终点.

### 管理外出应用程序

您可以创建、更新、删除或加载输出的应用程序 :

```typescript
// Create an outbound application.
// For DCR-based apps (e.g. custom MCP servers that support RFC 7591 dynamic
// client registration), pass `useDcr: true` and `dcrUrl`.
const { id } =
  await descopeClient.management.outboundApplication.createApplication({
    name: 'my new app',
    description: 'my desc',
    ...
  });

// Create an outbound application from a preconfigured app library template.
// The template (e.g. "hubspot", "google", "slack") prepopulates the provider's
// OAuth config - authorization/token endpoints, default scopes, pkce, etc.
// Any field set in `overrides` takes precedence over the template default.
const { id: templatedId } =
  await descopeClient.management.outboundApplication.createApplicationByTemplate({
    templateId: 'hubspot',
    clientId: 'my-client-id',
    clientSecret: 'my-client-secret',
    overrides: {
      name: 'HubSpot',
      // authorizationUrl / tokenUrl / defaultScopes / pkce inherited from the template
    },
  });

// Update an outbound application.
// Update will override all fields as is. Use carefully.
await descopeClient.management.outboundApplication.updateApplication({
  id: 'my-app-id',
  name: 'my updated app',
  ...
});

// delete an outbound appl
```

## 常见问题

### @descope/node-sdk 是什么？

用于与 Descope 集成的节点\.js 库

### 如何安装 @descope/node-sdk？

在项目目录运行 npm install @descope/node-sdk，或使用 pnpm add / yarn add / bun add。

### @descope/node-sdk 支持 TypeScript 吗？

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

### @descope/node-sdk 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @descope/node-sdk 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>= 18\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @descope/node-sdk 可以商用吗？

@descope/node-sdk 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @descope/node-sdk 的下载量有多少？

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

### @descope/node-sdk 还在维护吗？

最新版本 2\.22\.0 发布于 2026/11/11（今天）；至今共发布 638 个版本，其中过去 12 个月发布了 158 个；首次发布于 2022/08/16。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

