Microsoft 标识平台和 OAuth 2.0 设备权限授予流Microsoft identity platform and the OAuth 2.0 device authorization grant flow

Microsoft 标识平台支持设备权限授予,可让用户登录到智能电视、IoT 设备或打印机等输入受限设备。The Microsoft identity platform supports the device authorization grant, which allows users to sign in to input-constrained devices such as a smart TV, IoT device, or printer. 若要启用此流,设备会让用户在另一台设备上的浏览器中访问一个网页,以进行登录。To enable this flow, the device has the user visit a webpage in their browser on another device to sign in. 用户登录后,设备可以获取所需的访问令牌和刷新令牌。Once the user signs in, the device is able to get access tokens and refresh tokens as needed.

本文介绍如何在应用程序中直接针对协议进行编程。This article describes how to program directly against the protocol in your application. 如果可能,建议你改用受支持的 Microsoft 身份验证库 (MSAL) 来获取令牌并调用受保护的 Web APIWhen possible, we recommend you use the supported Microsoft Authentication Libraries (MSAL) instead to acquire tokens and call secured web APIs. 另请参阅使用 MSAL 的示例应用Also take a look at the sample apps that use MSAL.

协议图Protocol diagram

整个设备代码流如下图所示。The entire device code flow looks similar to the next diagram. 本文稍后介绍每个步骤。We describe each of the steps later in this article.

设备代码流

设备授权请求Device authorization request

客户端必须先在身份验证服务器中检查用于发起身份验证的设备代码和用户代码。The client must first check with the authentication server for a device and user code that's used to initiate authentication. 客户端从 /devicecode 终结点收集此请求。The client collects this request from the /devicecode endpoint. 在此请求中,客户端应包含需要从用户获取的权限。In this request, the client should also include the permissions it needs to acquire from the user. 从发送此请求的那一刻起,用户只有 15 分钟的时间(通常是 expires_in 的值)完成登录,因此,仅在用户指出他们已准备好登录时才发出此请求。From the moment this request is sent, the user has only 15 minutes to sign in (the usual value for expires_in), so only make this request when the user has indicated they're ready to sign in.

提示

尝试在 Postman 中执行此请求!Try executing this request in Postman! 尝试在 Postman 中运行此请求Try running this request in Postman

// Line breaks are for legibility only.

POST https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/devicecode
Content-Type: application/x-www-form-urlencoded

client_id=6731de76-14a6-49ae-97bc-6eba6914391e
scope=user.read%20openid%20profile

参数Parameter 条件Condition 说明Description
tenant 必须Required 可以是 /common 或 /organizations。Can be /common, or /organizations. 它也可以是要以 GUID 或友好名称格式向其请求权限的目录租户。It can also be the directory tenant that you want to request permission from in GUID or friendly name format.
client_id 必须Required Azure 门户 - 应用注册体验分配给应用的应用程序(客户端)IDThe Application (client) ID that the Azure portal - App registrations experience assigned to your app.
scope 必需Required 希望用户同意的范围的空格分隔列表。A space-separated list of scopes that you want the user to consent to.

设备授权响应Device authorization response

成功响应是一个 JSON 对象,其中包含允许用户登录所需的信息。A successful response will be a JSON object containing the required information to allow the user to sign in.

参数Parameter 格式Format 说明Description
device_code StringString 一个长字符串,用于验证客户端与授权服务器之间的会话。A long string used to verify the session between the client and the authorization server. 客户端使用此参数从授权服务器请求访问令牌。The client uses this parameter to request the access token from the authorization server.
user_code StringString 向用户显示的短字符串,用于标识辅助设备上的会话。A short string shown to the user that's used to identify the session on a secondary device.
verification_uri URIURI 用户在登录时应使用 user_code 转到的 URI。The URI the user should go to with the user_code in order to sign in.
expires_in intint device_codeuser_code 过期之前的秒数。The number of seconds before the device_code and user_code expire.
interval intint 在发出下一个轮询请求之前客户端应等待的秒数。The number of seconds the client should wait between polling requests.
message StringString 用户可读的字符串,包含面向用户的说明。A human-readable string with instructions for the user. 可以通过在请求中包含 ?mkt=xx-XX 格式的查询参数并填充相应的语言区域性代码,将此字符串本地化。This can be localized by including a query parameter in the request of the form ?mkt=xx-XX, filling in the appropriate language culture code.

备注

此时不包括或不支持 verification_uri_complete 响应字段。The verification_uri_complete response field is not included or supported at this time. 我们提到这一点是因为如果你阅读标准,你会看到 verification_uri_complete 作为设备代码流标准的可选部分列出。We mention this because if you read the standard you see that verification_uri_complete is listed as an optional part of the device code flow standard.

对用户进行身份验证Authenticating the user

收到 user_codeverification_uri 后,客户端会向用户显示这些信息,指示他们使用移动电话或电脑浏览器登录。After receiving the user_code and verification_uri, the client displays these to the user, instructing them to sign in using their mobile phone or PC browser.

尽管用户是在 verification_uri 中进行身份验证,但客户端应使用 device_code 来轮询所请求令牌的 /token 终结点。While the user is authenticating at the verification_uri, the client should be polling the /token endpoint for the requested token using the device_code.

POST https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type: urn:ietf:params:oauth:grant-type:device_code
client_id: 6731de76-14a6-49ae-97bc-6eba6914391e
device_code: GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8...
参数Parameter 必须Required 说明Description
tenant 必须Required 初始请求中使用的同一租户或租户别名。The same tenant or tenant alias used in the initial request.
grant_type 必须Required 必须是 urn:ietf:params:oauth:grant-type:device_codeMust be urn:ietf:params:oauth:grant-type:device_code
client_id 必须Required 必须与初始请求中使用的 client_id 匹配。Must match the client_id used in the initial request.
device_code 必须Required 设备授权请求中返回的 device_codeThe device_code returned in the device authorization request.

预期错误Expected errors

由于设备代码流是一个轮询协议,因此,客户端必须预料到在用户完成身份验证之前会收到错误。The device code flow is a polling protocol so your client must expect to receive errors before the user has finished authenticating.

错误Error 说明Description 客户端操作Client Action
authorization_pending 用户尚未完成身份验证,但未取消流。The user hasn't finished authenticating, but hasn't canceled the flow. 在至少 interval 秒之后重复请求。Repeat the request after at least interval seconds.
authorization_declined 最终用户拒绝了授权请求。The end user denied the authorization request. 停止轮询,并恢复到未经过身份验证状态。Stop polling, and revert to an unauthenticated state.
bad_verification_code 未识别已发送到 /token 终结点的 device_codeThe device_code sent to the /token endpoint wasn't recognized. 验证客户端是否在请求中发送了正确的 device_codeVerify that the client is sending the correct device_code in the request.
expired_token 至少已经过去了 expires_in 秒,不再可以使用此 device_code 进行身份验证。At least expires_in seconds have passed, and authentication is no longer possible with this device_code. 停止轮询,并恢复到未经过身份验证状态。Stop polling and revert to an unauthenticated state.

成功的身份验证响应Successful authentication response

成功的令牌响应如下:A successful token response will look like:

{
    "token_type": "Bearer",
    "scope": "User.Read profile openid email",
    "expires_in": 3599,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
    "refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4...",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyZDRkMTFhMi1mODE0LTQ2YTctOD..."
}
参数Parameter 格式Format 说明Description
token_type StringString 始终为“Bearer”。Always "Bearer.
scope 空格分隔的字符串Space separated strings 如果返回了访问令牌,则会列出该访问令牌的有效范围。If an access token was returned, this lists the scopes the access token is valid for.
expires_in intint 包含的访问令牌在生效之前所要经过的秒数。Number of seconds before the included access token is valid for.
access_token 不透明字符串Opaque string 针对请求的范围颁发。Issued for the scopes that were requested.
id_token JWTJWT 如果原始 scope 参数包含 openid 范围,则颁发。Issued if the original scope parameter included the openid scope.
refresh_token 不透明字符串Opaque string 如果原始 scope 参数包含 offline_access,则颁发。Issued if the original scope parameter included offline_access.

可以运行 OAuth 代码流文档中所述的同一个流,使用刷新令牌来获取新的访问令牌和刷新令牌。You can use the refresh token to acquire new access tokens and refresh tokens using the same flow documented in the OAuth Code flow documentation.