Goal / Context
I have a workflow in which information about my users is scattered between my client, Keycloak, and an internal database.
Based on a given claim_token
, I want to perform a lookup to further enrich identity tokens with custom claims.
The workflow is roughly as follows:
- a request for a token is performed
- a request to add information to the token (
uma-ticket
) is provided - a token with authentication, enriched data from the customer, lookup data from internal systems is assembled
Example flow / what has been tried?
POST http://my-keycloak-instance/auth/realms/my-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
client_id=my-client
&client_secret=super-secret
&grant_type=password
&scope=openid
&username=a-username
&password=a-password
Then we add some claim_token
information (that is only known to the client) to it:
POST http://my-keycloak-instance/auth/realms/my-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {{ token_from_above_response }}
accept: application/json
client_id=my-client
&grant_type=urn:ietf:params:oauth:grant-type:uma-ticket
&claim_token={{ to_jwt({department: ["sales", "accounting"], shoe_size: [36]}) }}
&claim_token_format=urn:ietf:params:oauth:token-type:jwt
&audience=an-audience
At this stage, I’d like a custom protocol mapper to use information that is given in claim_token
to perform a third-party API call and and create a custom claim, for example: departments: [71, 904]
.
I implemented a custom protocol mapper such as follows (pseudo-code: nullability has been accounted for in my final code):
public class MapCompanyIdAndOrganizationPositionToUserVisibilityGroupIdClaim
extends AbstractOIDCProtocolMapper
implements
OIDCAccessTokenMapper,
OIDCIDTokenMapper,
UserInfoTokenMapper {
// <SNIP>
@Override
public AccessToken transformAccessToken(
AccessToken token,
ProtocolMapperModel mappingModel,
KeycloakSession keycloakSession,
UserSessionModel userSession,
ClientSessionContext clientSessionCtx
) {
token.getOtherClaims()
.put("departments", someBusinessLogic(
token // ignore nullability/safety here: this is for making an example
.getAuthorization()
.getPermissions()
.stream()
.findFirst()
.get()
.getClaims()
));
return token;
}
}
What doesn’t work?
To my surprise, token.getAuthorization()
is always null
: this seems to be because custom protocol mappers are executed before authorization is evaluated.
This behavior is visible in these very lines, where the TokenManager
is responsible for running the various protocol mappers (under the hood):
https://github.com/keycloak/keycloak/blob/12732333c80db8478aa70556c62e3f71ede44cbd/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java#L357-L365
The question
How do I access the information that is in claim_token
(in the request) or in authorization
(in the produced token) from within a custom protocol mapper?