Device code flow in Keycloak

What is device code flow ?

Some devices do not have access to a web browser or a user input interface where to easily enter credentials. This includes smart TVs, or just console applications on servers where you can not load a web browser.

The device shows a code (“user_code”) which corresponds to a “login process”. The user has to copy this code, then a standard login process starts. The device polls an endpoint, the endpoint returns a token when the user completes the login process.

Endpoints

Take a look at your “open id endpoint configuration” (akka “well known”), there is 1 new endpoint :

And a new grant type :

  • urn:ietf:params:oauth:grant-type:device_code

You also have to use the /token endpoint.

Client

Create a new confidential client and enable “OAuth 2.0 Device Authorization Grant Enabled” :

The client has to be a confidential client.

Generate a user code

use the new “device” endpoint in a POST request with :

  • client_id
  • client_secret

This will generate a combo :

  • device_code : a confidential code, where to poll the token
  • user_code : an “authentication process id”
  • verification_uri : where to redirect the user to the authentication process
  • verification_uri_complete : the same, with the user_code in URI. Encode this in a QRCode.
  • expires_in
  • interval : for polling
curl --location --request POST 'https://app.please-open.it/auth/realms/--realmid--/protocol/openid-connect/auth/device' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=--client_id--' \
--data-urlencode 'client_secret=--client_secret--'

Authenticate

Open the “verification URI”, the “device” endpoint in the browser. It prompts for a user_code.

Or directly provide the code in the URL, with the “verification_uri_complete”.

Then the authentication process starts.

Get a token : polling

Using the /token endpoint, poll for a token with the new device code grant type. The link with the previous step is done with the “device_code” returned previously :

curl --location --request POST 'https://app.please-open.it/auth/realms/--realmid--/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'device_code=--device_code--' \
--data-urlencode 'client_id=--client_id--' \
--data-urlencode 'client_secret=--client_secret--' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' 

The endpoint returns :

{
    "error": "authorization_pending",
    "error_description": "The authorization request is still pending"
}

When the user has finished the authentication process, it returns a standard access_token/refresh_token structure as usual.

That’s it !