---
title: 身份验证
description: 所有 IDCloud 合约使用的 OAuth2 JWT Bearer 流程。了解如何获取凭据、构建 JWT assertion 并将其换取访问令牌。
canonical: https://developer.unico.io/zh-CN/dual-api/developers/api-reference/authentication
locale: zh-CN
generated_by: markdown-export
---

- [/zh-CN/](/zh-CN/)
- [API 参考](/zh-CN/dual-api/developers/api-reference/)
- 身份验证

**本页内容# 身份验证

所有 IDCloud API（Web & SDK 和 API 合约）均使用 **OAuth2 with JWT Bearer Grant Type**（[RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523)）。您在后端生成一个短期 JWT assertion，将其换取 Bearer 令牌，并在后续每次调用中使用该令牌。
请勿在客户端执行此操作JWT assertion 必须**仅在您的后端**生成。切勿在前端代码、移动应用、代码仓库或日志中暴露您的私钥。
### 获取凭据​

在生成令牌之前，您需要由 Unico 提供的**服务账号**。请联系 Unico 支持团队并提供以下信息：

服务账号名称（最多 12 个字符）
负责人的姓名、电子邮件和电话号码（仅限巴西、美国或墨西哥号码）

您将收到：

唯一账号名称
租户 ID
基础 JWT payload
私钥文件（`.pem` 格式）

每个环境一个账号请为 **UAT** 和**生产**环境分别保留独立的服务账号。
### 构建 JWT assertion​

assertion 是紧凑 JWS 格式的 JWT：`{Base64url(Header)}.{Base64url(Payload)}.{Base64url(Signature)}`。
Header
```
{  "alg": "RS256",  "typ": "JWT"}
```

Payload
声明值说明`iss``<account_name>@<tenant_id>.iam.acesso.io`随凭据一同提供`aud``https://identityhomolog.acesso.io`（UAT）或 `https://identity.acesso.io`（生产）必须与令牌端点主机匹配`scope``*`授予所有权限`iat`Unix 时间戳（秒）JWT 签发时间`exp``iat` + 最多 3600不得超过 `iat` 起 1 小时
```
{  "iss": "my-account@abc123.iam.acesso.io",  "aud": "https://identity.acesso.io",  "scope": "*",  "iat": 1738086000,  "exp": 1738089600}
```

Signature
使用 Unico 提  供的 `.pem` 私钥，通过 **RS256**（RSA + SHA-256）对 header + payload 进行签名。
请勿添加额外声明上述列表之外的任何字段（例如 `sub`、`jti`、`nbf`）都会导致 `1.2.22` 错误。请仅使用所示的声明。
### 请求令牌​

令牌端点对两种合约均相同：
环境端点**生产**`POST https://identity.acesso.io/oauth2/token`**UAT**`POST https://identityhomolog.acesso.io/oauth2/token`
Request
参数值`Content-Type``application/x-www-form-urlencoded``grant_type``urn:ietf:params:oauth:grant-type:jwt-bearer``assertion`您已签名的 JWT
cURLNode.jsPython```
curl -X POST https://identity.acesso.io/oauth2/token \  -H "Content-Type: application/x-www-form-urlencoded" \  -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \  -d "assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
```

```
import jwt from 'jsonwebtoken';import fs from 'fs';import qs from 'querystring';const privateKey = fs.readFileSync('./private-key.pem');const now = Math.floor(Date.now() / 1000);const assertion = jwt.sign(  {    iss: 'my-account@abc123.iam.acesso.io',    aud: 'https://identity.acesso.io',    scope: '*',    iat: now,    exp: now + 3600,  },  privateKey,  { algorithm: 'RS256' });const res = await fetch('https://identity.acesso.io/oauth2/token', {  method: 'POST',  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },  body: qs.stringify({    grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',    assertion,  }),});const { access_token, expires_in } = await res.json();
```

```
import timeimport jwt  # PyJWTimport requestswith open("private-key.pem", "rb") as f:    private_key = f.read()now = int(time.time())assertion = jwt.encode(    {        "iss": "my-account@abc123.iam.acesso.io",        "aud": "https://identity.acesso.io",        "scope": "*",        "iat": now,        "exp": now + 3600,    },    private_key,    algorithm="RS256",)response = requests.post(    "https://identity.acesso.io/oauth2/token",    data={        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",        "assertion": assertion,    },)token_data = response.json()access_token = token_data["access_token"]
```

Response
```
{  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",  "token_type": "Bearer",  "expires_in": 3600}
```

字段类型说明`access_token`stringJWT 访问令牌。在所有 API 调用中通过 `Authorization: Bearer <token>` 使用。`expires_in`integer过期时间（秒）。示例：`3600`。`token_type`string始终为 `Bearer`。
### 使用令牌​

在每个 API 请求的 `Authorization` 头中添加令牌。两种合约的头格式相同——不同之处在于所调用 API 的**主机和路径**：
合约生产主机UAT 主机**Web & SDK**`https://api.idcloud.unico.app``https://api.idcloud.uat.unico.app`**API**`https://api.id.unico.app``https://api.id.uat.unico.app`
**Web & SDK** — 仅需要 `Authorization` 头：
```
curl -X POST https://api.idcloud.unico.app/client/v1/process \  -H "Authorization: Bearer $ACCESS_TOKEN" \  -H "Content-Type: application/json" \  -d '{ ... }'
```

**API** — `Authorization` 与 `APIKEY` 头一起使用：
```
curl -X POST https://api.id.unico.app/processes/v1 \  -H "Authorization: Bearer $ACCESS_TOKEN" \  -H "APIKEY: $API_KEY" \  -H "Content-Type: application/json" \  -d '{ ... }'
```

### 令牌续期​

令牌在 3600 秒后过期。请在您的后端实现主动续期：

从令牌响应中跟踪 `expires_in` 并存储过期时间戳。
在过期前**剩余 10 分钟或更少时**请求新令牌。
切勿在生产环境中等待 `401` 响应才触发续期。

### API 参考​

令牌端点的完整 OpenAPI 规范可在 [`authentication.yaml`](/zh-CN/assets/files/authentication-1d221f9a7230435e9c390ba98dac7321.yaml) 中查看。
方法路径说明`POST``/oauth2/token`将已签名的 JWT assertion 换取 Bearer 访问令牌
### 错误代码​

代码说明处理方式`1.0.1``iss` 中提供的 ID 不正确验证 `iss` 字段是否与生成私钥时提供的租户 ID 匹配`1.0.14`应用程序未激活与项目经理确认所使用的应用程序是否已激活`1.1.1`未提供 `scope` 参数在 JWT payload 中添加 `"scope": "*"``1.2.4`JWT assertion 无效JWT assertion 已不再有效。两 种原因：(a) 当前时间已超过 `exp`（JWT 真正过期——每次令牌请求都应生成新的 assertion）；或 (b) `exp` 超过 `iat + 3600`（有效期过长——将 `exp` 上限设为 `iat + 3600`）。`1.2.5`JWT 验证失败无法验证 JWT。验证参数，并确保使用 RS256 和正确的私钥进行签名`1.2.6`私钥已失效用于签名 JWT 的私钥已不再有效。请为该账号申请新凭据`1.2.7`JWT 已被使用该 JWT 已被使用，不再有效。请为每次令牌请求生成新的 assertion`1.2.11`账号未激活所使用的账号未激活`1.2.14`账号缺少必要权限所使用的账号没有必要的权限`1.2.18`账号被临时锁定由于超过无效认证尝试次数，账号已被临时锁定`1.2.19`未授权的用户模拟JWT 包含指向未被授权模拟的账号的 `sub` 声明。请从 payload 中移除 `sub` 声明。`1.2.20`JWT 解码失败无法解码 JWT。请验证令牌格式及其是否使用 RS256 签名。`1.2.21`私钥错误/身份验证失败无法针对该账号的任何已知密钥验证 JWT 签名。请确认您使用的是此服务账号和环境对应的正确 `.pem` 私钥。`1.2.22`payload 中包含不允许的字段JWT 包含不允许的额外 payload 字段。请移除本指南未列出的任何声明（例如 `sub`、`jti`、`nbf`）。注意：若您包含了 `sub` 声明并收到了 `1.2.19` 错误，则该错误优先。`1.3.1`IP 访问限制您的 IP 不在该账号的白名单中`1.3.2`基于时间的访问限制请求超出该账号允许的时间窗口
### 下一步​

[环境](/zh-CN/dual-api/developers/api-reference/environments) — 沙箱与生产主机
[Web & SDK — 创建流程](/zh-CN/dual-api/developers/api-reference/web-sdk/post-process) — 认证后的首次调用
[API — 创建流程](/zh-CN/dual-api/developers/api-reference/api/post-processes) — 认证后的首次调用
[SSO / SAML](/zh-CN/dual-api/developers/api-reference/sso-saml) — 使用您自己的身份提供商为用户提供 Unico 产品门户的身份验证，而非上述的服务器到服务器流程
最后更新 于 2026年10月8日**