I have public client setup in keycloak. I have a custom scope under “Client Scopes” created and have a mapper - audience claim linked. I’ve added this scope to public client as optional scope, so it could be requested in request. The flow setup here is Auth flow with PKCE, with other settings being default for public client. I’ve already checked the mapper claim to be included in access token.
Issue:
When I load up my front-end app, it sends scope=“openid profile offline_access” during grant_type=auth flow process and gets the access, refresh and id tokens. These tokens doesn’t contain my custom scope and related claims, which is expected and fine. However, when the front-end app tried to make an api call (using refresh token with custom scope to get access token for it) in the request (scope=“openid profile offline_access mycustom_scope”), keycloak doesn’t send the custom scope nor claims in token.
Can we not request tokens with different scopes for different resources in keycloak ? is this the expected behavior, if so, how can I fix or configure keycloak to expect the behavior explained above ? Any help or guidance is greatly appreciated.
This is expected. A public client cannot use a token ( either refresh or access) to get more scope than initally requested. Just request the scope during inital access or use the BFF (backend for frontend) pattern ( google is your friend) to work with different tokens.
By initial access, you mean at auth code flow request ?
I’m bit confused as we are in process of move from azure b2c to keycloak as our authN and authZ needs and I see in azure, this is possible with public client and front-end angular/js library. The refresh token with custom scopes can request (delegated permissions) for access token specific for a resource (api) after initial request. Aren’t both keycloak and azure b2c implement the same oauth standard / framework flows ? For keycloak, if I include my custom scope in initial request, it would be applicable (since the refresh token will be reused again and again) for all resources (apis) calls but that is not the case here.
Don’t expect, that just because Microsoft (or any other vendor) does something and you used it, it is the proper way of doing this and part of any spec!
The refresh token is for a client being able to refresh the access token without user interaction. Here, the scope of the new issued token must not be wider than the initially issued token. However, it may(!) have a narrower scope, not never a broader scope.
See also [1] and [2].
What you want to achieve, getting a token with a different scope, is covered by the Token Exchange spec [3] and [4]. Token exchange in Keycloak is still not completely implemented, but your use case should be covered, see [5].
I guess, the public client pretty much just manages authentication part and retrieves the initial access token from keycloak. In our case, the backend api authorization is handled programmatically (thru user roles/permissions stored in a database), so I think, I can use same public client (both for front-end and backend app) as audience when I enable/setup secure authentication (JWT) for apis.