Search code examples
javakeycloak

How to configure a custom Keycloak token mapper to allow multivalued value


I created a custom Keycloak token mapper based on https://github.com/dasniko/keycloak-tokenmapper-example.

However, in my case, I wanted to add a list of values to the custom claim.

If I pass the list into mapClaim, it only uses the first element of the list:

List<MyObject> myList = ...
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, myList);

Solution

  • The solution is to add a static create method in the custom AbstractOIDCProtocolMapper subclass:

    public class MyCustomTokenMapper extends AbstractOIDCProtocolMapper
            implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
    
        ...
    
        public static ProtocolMapperModel create(String name,
                                                 boolean accessToken,
                                                 boolean idToken,
                                                 boolean userInfo) {
            ProtocolMapperModel mapper = new ProtocolMapperModel();
            mapper.setName(name);
            mapper.setProtocolMapper(PROVIDER_ID);
            mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
            Map<String, String> config = new HashMap<>();
            config.put(ProtocolMapperUtils.MULTIVALUED, Boolean.TRUE.toString()); // Set the MULTIVALUED config
            if (accessToken) {
                config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
            }
            if (idToken) {
                config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
            }
            if (userInfo) {
                config.put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, "true");
            }
            mapper.setConfig(config);
            return mapper;
        }
    }
    

    This static method is called automatically by Keycloak when it is present (For clarity, the custom mapper also works without it, but you can't configure the MULTIVALUED and the claim would only show the first item from the list). It allows to set the MULTIVALUED attribute to true so we can return a list of things.