Using device grant, how can I get an access token with openid scope?

Hello all. I’m trying to implement the “device authorization grant” using Keycloak 25.0.1. I successfully obtain an access token, but when I present the token to the well-known userinfo endpoint, Keycloak gives me a 403 Forbidden error, and the reason appears to be that the token does not contain the openid scope, even though I asked for it. Here are the response headers, notice the error_description:

In [19]: r.headers
Out[19]: Headers({'content-length': '0', 'content-type': 'text/plain;charset=utf-8',
'referrer-policy': 'no-referrer', 'strict-transport-security': 'max-age=31536000; 
includeSubDomains', 'www-authenticate': 'Bearer realm="reveal", error="insufficient_scope",
error_description="Missing openid scope"', 'x-content-type-options': 'nosniff', 'x-xss-protection':
'1; mode=block'})

So… am I misunderstanding the correct use of the device flow, can it never provide an openid scope? It provides email and profile scope information in the access token, so it certainly knows who the authenticating user is. Or is there something I’ve neglected to configure on the Keycloak side?

I decided on trying the device flow because my app is going to run in a docker container where there is no local browser that can be launched, so I can’t use the RFC-8252 native app flow. The device flow seems like the right flow for this scenario. Mumble.

Any advice very much appreciated! Meanwhile I continue to google…

The device authorization request can contain scopes in the same manner as the standrad flow does. I just checked it with Keycloak 24.0.5.: The access token contains the scope openid and a userinfo request is susscessful. In Keycloak 25, they moved some standard mappers to a new scope named basic. Is that scope added to your client as a default scope? If not, try to add this scope.

2 Likes

you should manually create a scope named openid

@mleib

1 Like

I’ve been pulled away on a high priority ticket, but I hope to try these suggestions Real Soon Now™. Thank you, @mbonn and @lamoboos223 !

1 Like

So… done with my firedrill, and I can now report back on what specifically I did to make it work.

First step was to manually create an openid client scope from the Client Scopes menu. Be sure to click the “include in token scope” checkbox. When the configuration gets exported, this results in adding the following JSON to the "clientScopes" list:

    {
      "id": "7a1187a4-fcc0-4b47-9415-465a85cc53ce",
      "name": "openid",
      "description": "OpenID Connect scope for device grant authentication",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "display.on.consent.screen": "true",
        "consent.screen.text": "OpenID identity"
      }
    },

Then I manually edited my client to add the openid scope as a “Default” scope. In the exported JSON, the result was that the "defaultClientScopes" list for my client got an "openid" entry.

And now life is beautiful. Thanks again for the responses!

1 Like