Configuring OAuth 2.0 Device Authorization Grant


The OAuth 2.0 Device Authorization Grant is designed for devices that are connected to the internet but lacks a browser to perform a user agent based authorization during an authorization flow. It enables devices such as TVs, printers to obtain user authorization to access a protected resource by using a user agent on a separate device.

The authorization flow is also referred to as device flow.

OAuth 2.0 Device Authorization Grant is an OAuth 2.0 extension that enables devices with no browser or limited input capability to obtain an access token.

Configuring provider.yml

  • The definition configuration defines a new grant_type urn:ietf:params:oauth:grant-type:device_code.
  • The definition configuration defines a set of device_flow_settings.
ConfigurationDescriptionDefault value
device_flow_polling_interval_in_secsPolling interval in seconds5 seconds
device_flow_codelifetime_in_secsValidity of the device code in seconds300 seconds
device_flow_usercode_lengthLength of the user code. Has to be set to a value greater than 66
device_flow_usercode_charsetCharacter set for user code, should be characters that are unique and greater than the code lengthABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
enforce_clientauth_device_authorizeTo enforce client authentication at the device authorization endpointtrue
# Copyright contributors to the IBM Security Verify Access OIDC Provider Resources project
version: 24.06
  level: debug
  id: 1
  name: OIDC Definition
    - authorization_code
    - password
    - client_credentials
    - implicit
    - refresh_token
    - urn:ietf:params:oauth:grant-type:token-exchange    
    - urn:ietf:params:oauth:grant-type:jwt-bearer 
    - urn:ietf:params:oauth:grant-type:device_code    
  pre_mappingrule_id: isvaop_pretoken                       # Pre-Token mapping rule ID.
  post_mappingrule_id: isvaop_posttoken  
  token_settings:                                           # Token Settings
    issuer:                          # OP's issuer URI.
    signing_alg: PS256                                      # Signing algorithm for ID token generated.
    signing_keystore: isvaop_signing                        # Signing keystore name.
    signing_keylabel: jwtsigning                            # Signing key label.
    device_flow_polling_interval_seconds: 10
    device_flow_codelifetime_seconds: 300
    device_flow_usercode_length: 7
    device_flow_usercode_charset: 'ABCD1234'
    enforce_clientauth_device_authorize: true
  attribute_map:                                            # Attribute mapping to resolve claims. also refer to attributesources.yml
    surname: surname  
    key: ks:isvaop_keys/httpserverkey
    certificate: ks:isvaop_keys/httpservercert
  signing_keystore: isvaop_signing
  obf_key: "ENC:iUt+3MzCntxSL2FPTUuJqER79UaiRSApMz3cbgJm4yzuiv6H7KN8ADsamX6+Qre1oTsATjnb1bJ0Lmi7WWfxWeGT477yqqvgVayFlCDIFzZeNkdINjASfTE3B+/3Sm9YjIYuWtZdySiXeydhJXSiOGU9osdA9g2BZXR4eMrXNutCuaSvFH6MY+TyOH5q15vy6vEWOebJQHrnug0A8rN6NF8G8XaxCe/+yqH57jJpdhm0N7iUydIYOBOQ1wDgCc8nRMWkQqlkcRhDZvLLAIlhoshYvo06ubyryt8/vv/0AvTLq9AIiQoL8CtYLr+SNZlzWe4CnHYZdO9S+AIrUOVORw=="
  enc_key: "@keys/private.pem"

Configuring a confidential client

  • Enable a new grant type called urn:ietf:params:oauth:grant-type:device_code.
  • Since it is a confidential client set token_endpoint_auth_method to client_secret_post.
# Copyright contributors to the IBM Security Verify Access OIDC Provider Resources project
  - client_id: client01deviceflow
    client_secret: "OBF:U2FsdGVkX19iBhlwc53QkybjO6RjFHhSbz4VRudYHA="                                            # Client secret that is used for client authentication and/or JWT signing/encryption. `OBF:` indicates obfuscated string.
    client_name: TV Console                                                                              # Name of the client.
    client_id_issued_at: 1642399207                                                                             # Timestamp (in seconds) from when the client is created.
    enabled: true                                                                                               # Set to `true` to enable this client
    grant_types:                                                                                                # Grant type that the client is allowed to use at the token endpoint.
      - authorization_code
      - password
      - client_credentials
      - implicit
      - refresh_token
      - urn:openid:params:grant-type:ciba
      - urn:ietf:params:oauth:grant-type:token-exchange 
      - urn:ietf:params:oauth:grant-type:jwt-bearer
    response_types:                                                                                             # Response type that the client is allowed to use at the authorization endpoint.
      - code id_token
      - code
      - code token
      - none
      - code token id_token
    redirect_uris:                                                                                              # Redirection URI strings for use in redirect-based flows such as the authorization code and implicit flows.
    request_uris:                                                                                               # Request URIs that are pre-registered by the Relying Party for use at the OIDC Provider.
    scopes:                                                                                                     # A list of scope values that the client can use when requesting access tokens.
      - cdr:registration
      - openid
      - profile
    id_token_signed_response_alg: PS512                                                                         
    token_endpoint_auth_method: client_secret_post                                                               

Initiating a device authorization request

  • The TV console client initiates a device_authorization request.
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=client01deviceflow' \
--data-urlencode 'client_secret=asfasdfawqdewq'
  • Client authentication is set to client_secret_post, hence client_id and client_secret are sent in the post payload.
    "device_code": "YZiWfi7VRurn7_xv3Yk1zn45Qa3KegWHg-hZcK9es74.bi8TlAok2_9EBnTSOA0mTMX47Wo23ewQSuGIJJtxFpEfkYGvk15DbkoCVxocn8gZAqbTrm6l8GzN6mE7ZJIWDA",
    "expires_in": 300,
    "interval": 5,
    "user_code": "OLZYDQT",
    "verification_uri": "",
    "verification_uri_complete": ""



To run device flow, set the user_authorize endpoint to the ACL at Web reverse proxy to anyauth.

User authorization

  • The end user then launches the verification_uri, and provides the user_code that it receives.
  • Optionally the verification_uri_complete might be displayed on the TV console as a QR Code.
  • The user may be asked for consent based on the consent_prompt: ALWAYS_PROMPT.

Polling the token endpoint

  • The TV console polls the token endpoint to check if the user has authorized the device code.
  • The polling interval determines the frequency with which token endpoint is called.
curl --location '' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=client01deviceflow' \
--data-urlencode 'client_secret=asfasdfawqdewq' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
--data-urlencode 'device_code=YZiWfi7VRurn7_xv3Yk1zn45Qa3KegWHg-hZcK9es74.bi8TlAok2_9EBnTSOA0mTMX47Wo23ewQSuGIJJtxFpEfkYGvk15DbkoCVxocn8gZAqbTrm6l8GzN6mE7ZJIWDA'
  • If the device code is not authorized a authorization_pending error code is received.
    "error": "authorization_pending",
    "error_description": "The user has not authorized the request."
  • If the client is polling the token endpoint more frequently than the defined interval slow_down error code is received.
    "error": "slow_down",
    "error_description": "The device made an attempt within [5] seconds. This request will not be processed."
  • If the device code is authorized successfully, tokens are returned as a part of response.
    "access_token": "dlDKljQrSlBjyTziK0x00XTKG50T_gG2uI9MfWEz3wU.qo_7P4X0qmek2f5G5GXs3UirfeBOfxWpdK8vv7B-phAceUONCC0a3b7Wkpc0ogggRd1ojtXvDEXOQWeRD92-3g",
    "expires_in": 7199,
    "refresh_token": "ukO8SCM8WBxj8cJpmEVzS8ktT0yHdXsdU40B85KhbUM.vx7EoWxAIpYoASSoG4sTMHngA9bnIgcDvdYKaoRhvzyenzigXr0nH25F3ckOOiZiG8FohLFRqmp6fka2kCWLbg",
    "scope": "openid",
    "token_type": "bearer"