From some times now (release 13.0) Keycloak supports device code flow which can be very usefull in some cases. The device code flow is an OAuth 2.0 authorization flow used by applications that cannot securely store a client secret, such as applications installed on devices like TVs, interactive voice response systems, and printers. This flow is used to obtain an access token that can then be used to access a protected resource. In Keycloak, the device code flow works by the user entering a code displayed on their device into a web browser to authenticate with Keycloak. Once authenticated, Keycloak will return an access token that can be used to access the protected resource.

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 :

  • https://app.please-open.it/auth/realms/–realmid–/protocol/openid-connect/auth/device

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 » :

Device Code Flow in Keycloak

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.

Device Code Flow in Keycloak

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 !

Mathieu PASSENAUD
Les derniers articles par Mathieu PASSENAUD (tout voir)