RFC8628: OAuth 2.0 Device Authorization Grant

This section contains the generic implementation of RFC8628.

API Reference

class authlib.oauth2.rfc8628.DeviceAuthorizationEndpoint(server)

This OAuth 2.0 [RFC6749] protocol extension enables OAuth clients to request user authorization from applications on devices that have limited input capabilities or lack a suitable browser. Such devices include smart TVs, media consoles, picture frames, and printers, which lack an easy input method or a suitable browser required for traditional OAuth interactions. Here is the authorization flow:

+----------+                                +----------------+
|          |>---(A)-- Client Identifier --->|                |
|          |                                |                |
|          |<---(B)-- Device Code,      ---<|                |
|          |          User Code,            |                |
|  Device  |          & Verification URI    |                |
|  Client  |                                |                |
|          |  [polling]                     |                |
|          |>---(E)-- Device Code       --->|                |
|          |          & Client Identifier   |                |
|          |                                |  Authorization |
|          |<---(F)-- Access Token      ---<|     Server     |
+----------+   (& Optional Refresh Token)   |                |
      v                                     |                |
      :                                     |                |
     (C) User Code & Verification URI       |                |
      :                                     |                |
      v                                     |                |
+----------+                                |                |
| End User |                                |                |
|    at    |<---(D)-- End user reviews  --->|                |
|  Browser |          authorization request |                |
+----------+                                +----------------+

This DeviceAuthorizationEndpoint is the implementation of step (A) and (B).

  1. The client requests access from the authorization server and includes its client identifier in the request.
  2. The authorization server issues a device code and an end-user code and provides the end-user verification URI.
USER_CODE_TYPE = 'string'

customize “user_code” type, string or digital

EXPIRES_IN = 1800

The lifetime in seconds of the “device_code” and “user_code”

INTERVAL = 5

The minimum amount of time in seconds that the client SHOULD wait between polling requests to the token endpoint.

generate_user_code()

A method to generate user_code value for device authorization endpoint. This method will generate a random string like MQNA-JPOZ. Developers can rewrite this method to create their own user_code.

generate_device_code()

A method to generate device_code value for device authorization endpoint. This method will generate a random string of 42 characters. Developers can rewrite this method to create their own device_code.

get_verification_uri()

Define the verification_uri of device authorization endpoint. Developers MUST implement this method in subclass:

def get_verification_uri(self):
    return 'https://your-company.com/active'
save_device_credential(client_id, scope, data)

Save device token into database for later use. Developers MUST implement this method in subclass:

def save_device_credential(self, client_id, scope, data):
    item = DeviceCredential(
        client_id=client_id,
        scope=scope,
        **data
    )
    item.save()
class authlib.oauth2.rfc8628.DeviceCodeGrant(request, server)

This OAuth 2.0 [RFC6749] protocol extension enables OAuth clients to request user authorization from applications on devices that have limited input capabilities or lack a suitable browser. Such devices include smart TVs, media consoles, picture frames, and printers, which lack an easy input method or a suitable browser required for traditional OAuth interactions. Here is the authorization flow:

+----------+                                +----------------+
|          |>---(A)-- Client Identifier --->|                |
|          |                                |                |
|          |<---(B)-- Device Code,      ---<|                |
|          |          User Code,            |                |
|  Device  |          & Verification URI    |                |
|  Client  |                                |                |
|          |  [polling]                     |                |
|          |>---(E)-- Device Code       --->|                |
|          |          & Client Identifier   |                |
|          |                                |  Authorization |
|          |<---(F)-- Access Token      ---<|     Server     |
+----------+   (& Optional Refresh Token)   |                |
      v                                     |                |
      :                                     |                |
     (C) User Code & Verification URI       |                |
      :                                     |                |
      v                                     |                |
+----------+                                |                |
| End User |                                |                |
|    at    |<---(D)-- End user reviews  --->|                |
|  Browser |          authorization request |                |
+----------+                                +----------------+

This DeviceCodeGrant is the implementation of step (E) and (F).

  1. While the end user reviews the client’s request (step D), the client repeatedly polls the authorization server to find out if the user completed the user authorization step. The client includes the device code and its client identifier.
  2. The authorization server validates the device code provided by the client and responds with the access token if the client is granted access, an error if they are denied access, or an indication that the client should continue to poll.
validate_token_request()

After displaying instructions to the user, the client creates an access token request and sends it to the token endpoint with the following parameters:

grant_type
REQUIRED. Value MUST be set to “urn:ietf:params:oauth:grant-type:device_code”.
device_code
REQUIRED. The device verification code, “device_code” from the device authorization response.
client_id
REQUIRED if the client is not authenticating with the authorization server as described in Section 3.2.1. of [RFC6749]. The client identifier as described in Section 2.2 of [RFC6749].

For example, the client makes the following HTTPS request:

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code
&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
&client_id=1406020730
create_token_response()

If the access token request is valid and authorized, the authorization server issues an access token and optional refresh token.

authenticate_token_endpoint_client()

Authenticate client with the given methods for token endpoint.

For example, the client makes the following HTTP request using TLS:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

Default available methods are: “none”, “client_secret_basic” and “client_secret_post”.

Returns:client
query_device_credential(device_code)

Get device credential from previously savings via DeviceAuthorizationEndpoint. Developers MUST implement it in subclass:

def query_device_credential(self, device_code):
    return DeviceCredential.query.get(device_code)
Parameters:device_code – a string represent the code.
Returns:DeviceCredential instance
query_user_grant(user_code)

Get user and grant via the given user code. Developers MUST implement it in subclass:

def query_user_grant(self, user_code):
    # e.g. we saved user grant info in redis
    data = redis.get('oauth_user_grant:' + user_code)
    if not data:
        return None

    user_id, allowed = data.split()
    user = User.query.get(user_id)
    return user, bool(allowed)

Note, user grant information is saved by verification endpoint.

should_slow_down(credential, now)

The authorization request is still pending and polling should continue, but the interval MUST be increased by 5 seconds for this and all subsequent requests.

save_token(token)

A method to save token into database.

validate_requested_scope()

Validate if requested scope is supported by Authorization Server.