

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 令牌发布者端点
<a name="token-endpoint"></a>

的 OAuth 2.0 [令牌端点](https://www.rfc-editor.org/rfc/rfc6749#section-3.2)向想要完成授权码和客户端凭证授予流程的应用程序`/oauth2/token`发放 JSON Web 令牌 (JWTs)。这些令牌是使用用户池进行身份验证的最终结果。这些令牌包含有关用户（ID 令牌）、用户的访问级别（访问令牌）以及用户保留其已登录会话的权利（刷新令牌）的信息。OpenID Connect（OIDC）依赖方库处理向此端点发出的请求以及来自此端点的响应有效载荷。令牌提供可验证的身份验证证明、配置文件信息以及用于访问后端系统的机制。

您的用户池 OAuth 2.0 授权服务器从令牌端点向以下类型的会话发放 JSON Web 令牌 (JWTs)：

1. 已完成授权码授权请求的用户。成功兑换代码会返回 ID、访问令牌和刷新令牌。

1. Machine-to-machine (M2M) 已完成客户端凭证授予的会话。成功使用客户端机密进行授权会返回访问令牌。

1. 之前已登录并收到刷新令牌的用户。刷新令牌身份验证会返回新的 ID 令牌和访问令牌。
**注意**  
在托管登录中使用授权码授予或通过联合身份验证登录的用户可以随时从令牌端点刷新其令牌。当[记忆设备](amazon-cognito-user-pools-device-tracking.md)在您的用户池中*未*处于活动状态时，使用 API 操作 `InitiateAuth` 和 `AdminInitiateAuth` 登录的用户可以使用令牌端点刷新其令牌。如果记忆设备处于活动状态，请使用应用程序客户端的[相关 API 或 SDK 令牌刷新操作](amazon-cognito-user-pools-using-the-refresh-token.md#using-the-refresh-token-api)刷新令牌。

当您向用户池添加域时，令牌端点将公开可用。它接受 HTTP POST 请求。为了实现应用程序安全性，请将 PKCE 与授权代码登录事件结合使用。PKCE 会验证传递授权码的用户是否与经过身份验证的用户相同。有关 PKCE 的更多信息，请参阅 [IETF RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)。

要详细了解用户池应用程序客户端及其授权类型、客户端密钥、允许的范围和客户端，请 IDs 访问[特定于应用程序的应用程序客户端设置](user-pool-settings-client-apps.md)。要详细了解 M2M 授权、客户端凭证授权以及使用访问令牌范围的授权，请访问[作用域、M2M 和资源服务器](cognito-user-pools-define-resource-servers.md)。

要从用户的访问令牌中检索有关用户的信息，可以将其传递给 [userInfo 端点](userinfo-endpoint.md) 或 [https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_GetUser.html](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_GetUser.html) API 请求。访问令牌必须包含这些请求的相应范围，

## 为向令牌端点的 POST 请求设置格式
<a name="post-token"></a>

`/oauth2/token` 端点只支持 `HTTPS POST`。此端点非用户交互式。请在您的应用程序中使用 [OpenID Connect（OIDC）库](https://openid.net/developers/certified-openid-connect-implementations/)处理令牌请求。

令牌端点支持 `client_secret_basic` 和 `client_secret_post` 身份验证。有关 OIDC 规范的更多信息，请参阅[客户端身份验证](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication)。有关 OpenID Connect 规范中令牌端点的更多信息，请参阅[令牌端点](http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint)。

### 标头中的请求参数
<a name="post-token-request-parameters"></a>

您可以将请求标头中的以下参数传递给令牌端点。

**`Authorization`**  
如果向客户端发布了密钥，则客户端可以在授权标头中将其 `client_id` 和 `client_secret` 作为 `client_secret_basic` HTTP 授权传递。您还可以在请求正文中包含 `client_id` 和 `client_secret` 作为 `client_secret_post` 授权。  
授权标头字符串是 [基本](https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side) `Base64Encode(client_id:client_secret)`。以下示例是具有客户端密钥 `abcdef01234567890` 的应用程序客户端 `djc98u3jiedmi283eu928` 的授权标头，其使用字符串 `djc98u3jiedmi283eu928:abcdef01234567890` 的 Base64 编码版本：  

```
Authorization: Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw
```

**`Content-Type`**  
将此参数的值设置为 `'application/x-www-form-urlencoded'`。

### 正文中的请求参数
<a name="post-token-request-parameters-in-body"></a>

以下是您可以在请求正文中以 `x-www-form-urlencoded` 格式向令牌端点请求的参数。

**`grant_type`**  
*必填项*。  
要请求的 OIDC 授予的类型。  
必须为 `authorization_code`、`refresh_token` 或 `client_credentials`。在以下条件下，您可以从令牌端点请求自定义范围的访问令牌：  
+ 您在应用程序客户端配置中启用请求的范围。
+ 您为应用程序客户端配置了客户端密钥。
+ 您在应用程序客户端中启用客户端凭证授予。
仅当 `grant_type` 为 `authorization_code` 时，令牌端点才返回刷新令牌。

**`client_id`**  
*可选。当您在 `Authorization` 标头中提供应用程序客户端 ID 时不是必需项。*  
用户池中应用程序客户端的 ID。指定对用户进行身份验证的同一个应用程序客户端。  
如果客户端为公有且没有密钥，或在 `client_secret_post` 授权中有 `client_secret`，则必须提供此参数。

**`client_secret`**  
*可选。当您在 `Authorization` 标头中提供客户端密钥以及应用程序客户端没有密钥时不是必需项。*  
用于 `client_secret_post` 授权的应用程序客户端密钥（如果应用程序客户端有的话）。

**`scope`**  
*可选。*  
可以是与应用程序客户端关联的任何范围的组合。Amazon Cognito 会忽略请求中对于请求的应用程序客户端来说不允许使用的范围。如果您不提供此请求参数，则授权服务器会返回访问令牌 `scope` 声明，其中包含您在应用程序客户端配置中启用的所有授权范围。您可以请求对于请求的应用程序客户端来说允许使用的任何范围：标准范围、来自资源服务器的自定义范围以及 `aws.cognito.signin.user.admin` 用户自助范围。

**`redirect_uri`**  
*可选。授予客户端凭证时不是必需项。*  
必须是用于在 `/oauth2/authorize` 中获取 `authorization_code` 的相同 `redirect_uri`。  
如果 `grant_type` 是 `authorization_code`，则必须提供此参数。

**`refresh_token`**  
*可选。仅当用户已经拥有刷新令牌并希望获得新 ID 和访问令牌时使用。*  
要为用户的会话生成新的访问令牌和 ID 令牌，请将 `refresh_token` 的值设置为请求的应用程序客户端发布的有效刷新令牌。  
当[刷新令牌轮换](amazon-cognito-user-pools-using-the-refresh-token.md#using-the-refresh-token-rotation)处于活动状态时，返回带有新 ID 和访问令牌的新刷新令牌，否则仅返回 ID 和访问令牌。如果原始访问令牌[绑定到 API 资源](cognito-user-pools-define-resource-servers.md#cognito-user-pools-resource-binding)，则新的访问令牌会在 `aud` 声明中保留请求的 API URL。

**`code`**  
*可选。仅在授予授权码时必需。*  
来自授权码授予的授权码。如果授权请求包括 `authorization_code` 的 `grant_type`，则必须提供此参数。

**`aws_client_metadata`**  
*可选。*  
您要传递给输入 [machine-to-machine (M2M)](cognito-user-pools-define-resource-servers.md) 授权流程的信息。[令牌生成前 Lambda 触发器](user-pool-lambda-pre-token-generation.md)您的应用程序可以收集有关会话的上下文信息，并将其传递到此参数中。当您以 URL 编码的 JSON 格式传递 `aws_client_metadata` 时，Amazon Cognito 会将其包含在触发器 Lambda 函数的输入事件中。令牌生成前触发器事件版本或全局 Lambda 触发器版本必须针对版本三或更高版本进行配置。尽管 Amazon Cognito 在授权码和客户端凭证 M2M 流程中接受对该端点的请求，但用户池仅从客户端凭证请求将 `aws_client_metadata` 传递到令牌生成前触发器。

**`code_verifier`**  
可选。仅当您在初始授权请求中提供了 `code_challenge_method` 和 `code_challenge` 参数时才必需。  
您的应用程序在 [PKCE](using-pkce-in-authorization-code.md) 的授权码授予请求中计算 `code_challenge` 的生成的代码验证程序。

## 为获取令牌交换授权代码
<a name="post-token-positive-exchanging-authorization-code-for-tokens"></a>

在通过授权码授予进行身份验证后，以下请求成功生成 ID、访问和刷新令牌。请求在 `Authorization` 标头中以 `client_secret_basic` 格式传递客户端密钥。

```
POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token&
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw

grant_type=authorization_code&
client_id=1example23456789&
code=AUTHORIZATION_CODE&
redirect_uri=com.myclientapp://myclient/redirect
```

响应向用户发布新的 ID、访问和刷新令牌以及其他元数据。

```
HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJra1example",
    "id_token": "eyJra2example",
    "refresh_token": "eyJj3example",
    "token_type": "Bearer",
    "expires_in": 3600
}
```

## 基本授权的客户端凭证
<a name="exchanging-client-credentials-for-an-access-token-in-request-body"></a>

以下来自 M2M 应用程序的请求用于请求授予客户端凭证。由于客户端凭证需要客户端密钥，因此使用从应用程序客户端 ID 和密钥派生的 `Authorization` 标头对请求进行授权。该请求会生成一个具有两个请求范围的访问令牌。该请求还包括客户端元数据，在其中提供 IP 地址信息以及向此授予代表的用户发布的令牌。Amazon Cognito 将客户端元数据传递给令牌生成前 Lambda 触发器。

```
POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token >
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw

grant_type=client_credentials&
client_id=1example23456789&
scope=resourceServerIdentifier1%2Fscope1%20resourceServerIdentifier2%2Fscope2&
&aws_client_metadata=%7B%22onBehalfOfToken%22%3A%22eyJra789ghiEXAMPLE%22,%20%22ClientIpAddress%22%3A%22192.0.2.252%22%7D
```

Amazon Cognito 将以下输入事件传递给令牌生成前 Lambda 触发器。

```
{
    version: '3',
    triggerSource: 'TokenGeneration_ClientCredentials',
    region: 'us-east-1',
    userPoolId: 'us-east-1_EXAMPLE',
    userName: 'ClientCredentials',
    callerContext: {
        awsSdkVersion: 'aws-sdk-unknown-unknown',
        clientId: '1example23456789'
    },
    request: {
        userAttributes: {},
        groupConfiguration: null,
        scopes: [
           'resourceServerIdentifier1/scope1',
           'resourceServerIdentifier2/scope2'
        ],
        clientMetadata: {
            'onBehalfOfToken': 'eyJra789ghiEXAMPLE',
            'ClientIpAddress': '192.0.2.252'
        }
    },
    response: { claimsAndScopeOverrideDetails: null }
}
```

响应返回访问令牌。客户凭证授予用于 machine-to-machine（M2M）授权，并且仅返回访问令牌。

```
HTTP/1.1 200 OK
Content-Type: application/json
{
    "access_token": "eyJra1example",
    "token_type": "Bearer",
    "expires_in": 3600
}
```

## POST 正文授权的客户端凭证
<a name="post-token-positive-exchanging-client-credentials-for-an-access-token-in-request-body"></a>

以下客户端凭证授予请求在请求正文中包含 `client_secret` 参数，但是不包含 `Authorization` 标头。此请求使用 `client_secret_post` 授权语法。该请求会生成一个具有所请求范围的访问令牌。该请求还包括客户端元数据，在其中提供 IP 地址信息以及向此授予代表的用户发布的令牌。Amazon Cognito 将客户端元数据传递给令牌生成前 Lambda 触发器。

```
POST /oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
X-Amz-Target: AWSCognitoIdentityProviderService.Client credentials request
User-Agent: USER_AGENT
Accept: /
Accept-Encoding: gzip, deflate, br
Content-Length: 177
Referer: http://auth.example.com/oauth2/token
Host: auth.example.com
Connection: keep-alive

grant_type=client_credentials&
client_id=1example23456789&
scope=my_resource_server_identifier%2Fmy_custom_scope&
client_secret=9example87654321&
aws_client_metadata=%7B%22onBehalfOfToken%22%3A%22eyJra789ghiEXAMPLE%22,%20%22ClientIpAddress%22%3A%22192.0.2.252%22%7D
```

Amazon Cognito 将以下输入事件传递给令牌生成前 Lambda 触发器。

```
{
    version: '3',
    triggerSource: 'TokenGeneration_ClientCredentials',
    region: 'us-east-1',
    userPoolId: 'us-east-1_EXAMPLE',
    userName: 'ClientCredentials',
    callerContext: {
        awsSdkVersion: 'aws-sdk-unknown-unknown',
        clientId: '1example23456789'
    },
    request: {
        userAttributes: {},
        groupConfiguration: null,
        scopes: [
           'resourceServerIdentifier1/my_custom_scope'
        ],
        clientMetadata: {
            'onBehalfOfToken': 'eyJra789ghiEXAMPLE',
            'ClientIpAddress': '192.0.2.252'
        }
    },
    response: { claimsAndScopeOverrideDetails: null }
}
```

响应返回访问令牌。客户凭证授予用于 machine-to-machine（M2M）授权，并且仅返回访问令牌。

```
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Date: Tue, 05 Dec 2023 16:11:11 GMT
x-amz-cognito-request-id: 829f4fe2-a1ee-476e-b834-5cd85c03373b

{
    "access_token": "eyJra12345EXAMPLE",
    "expires_in": 3600,
    "token_type": "Bearer"
}
```

## PKCE 的授权码授予
<a name="post-token-positive-exchanging-authorization-code-grant-with-pkce-for-tokens"></a>

以下示例请求完成在 [PKCE](using-pkce-in-authorization-code.md) 的授权码授予请求中包含 `code_challenge_method` 和 `code_challenge` 参数的授权请求。

```
POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw

grant_type=authorization_code&
client_id=1example23456789&
code=AUTHORIZATION_CODE&
code_verifier=CODE_VERIFIER&
redirect_uri=com.myclientapp://myclient/redirect
```

响应从应用程序的成功 PKCE 验证中返回 ID、访问和刷新令牌。

```
HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJra1example",
    "id_token": "eyJra2example",
    "refresh_token": "eyJj3example",
    "token_type": "Bearer",
    "expires_in": 3600
}
```

## 无刷新令牌轮换的令牌刷新
<a name="post-token-positive-exchanging-a-refresh-token-for-tokens"></a>

以下示例请求向[刷新令牌轮换](amazon-cognito-user-pools-using-the-refresh-token.md#using-the-refresh-token-rotation)不处于活动状态的应用程序客户端提供刷新令牌。由于应用程序客户端有客户端密钥，因此请求会提供 `Authorization` 标头。

```
POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token >
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw

grant_type=refresh_token&
client_id=1example23456789&
refresh_token=eyJj3example
```

响应返回新的 ID 令牌和访问令牌。

```
HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJra1example",
    "id_token": "eyJra2example",
    "token_type": "Bearer",
    "expires_in": 3600
}
```

## 带刷新令牌轮换的令牌刷新
<a name="post-token-positive-refresh-token-rotation"></a>

以下示例请求向[刷新令牌轮换](amazon-cognito-user-pools-using-the-refresh-token.md#using-the-refresh-token-rotation)处于活动状态的应用程序客户端提供刷新令牌。由于应用程序客户端有客户端密钥，因此请求会提供 `Authorization` 标头。

```
POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token >
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw

grant_type=refresh_token&
client_id=1example23456789&
refresh_token=eyJj3example
```

响应返回新的 ID、访问和刷新令牌。

```
HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJra1example",
    "id_token": "eyJra2example",
    "refresh_token": "eyJj4example",
    "token_type": "Bearer",
    "expires_in": 3600
}
```

## 负向响应的示例
<a name="post-token-negative"></a>

格式错误的请求会从令牌端点生成错误。以下是令牌请求生成错误时响应正文的大致示意图。

```
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8

{
"error":"invalid_request|invalid_client|invalid_grant|unauthorized_client|unsupported_grant_type"
}
```

**`invalid_request`**  
请求缺少必需的参数、包括不支持的参数值（除了 `unsupported_grant_type` 之外）或者格式错误。例如，`grant_type` 是 `refresh_token`，但未包括 `refresh_token`。

**`invalid_client`**  
客户端身份验证失败。例如，客户端的授权标头中包含 `client_id` 和 `client_secret`，但没有这样的客户端带有 `client_id` 和 `client_secret`。

**`invalid_grant`**  
已撤销刷新令牌。  
授权代码已使用或不存在。  
应用程序客户端对请求的范围内的所有[属性](https://docs.amazonaws.cn/cognito/latest/developerguide/user-pool-settings-attributes.html)都没有读取权限。例如，您的应用程序请求 `email` 范围，应用程序客户端可以读取 `email` 属性，但不能读取 `email_verified`。

**`unauthorized_client`**  
客户端不允许代码授予流或刷新令牌。

**`unsupported_grant_type`**  
如果 `grant_type` 是 `authorization_code`、`refresh_token` 或 `client_credentials` 之外的任意内容，则返回。