Search code examples
jacksonkeycloakresteasyjackson-databindjackson-annotations

keycloak : Unrecognized field "access_token"


I've a problem with the keycloak admin client.

When I try to do :

// Création d'un client Keycloak
            Keycloak keycloak = KeycloakBuilder.builder()
                    .serverUrl(keycloakUrlAuth)
                    .realm(keycloakRealm)
                    .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
                    .clientId(keycloakClientId)
                    .clientSecret(keycloakClientSecret)
                    .build();
            // Obtention du token d'accès
            AccessTokenResponse token = keycloak.tokenManager().getAccessToken();
            return token.getToken();

I always get this error :

at [Source: (org.jboss.resteasy.client.jaxrs.internal.ClientResponse$InputStreamWrapper); line: 1, column: 18] (through reference chain: org.keycloak.representations.AccessTokenResponse["access_token"]): javax.ws.rs.client.ResponseProcessingException: javax.ws.rs.ProcessingException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "access_token" (class org.keycloak.representations.AccessTokenResponse), not marked as ignorable (10 known properties: "tokenType", "notBeforePolicy", "otherClaims", "token", "sessionState", "refreshExpiresIn", "scope", "expiresIn", "refreshToken", "idToken"])
docker-jboss-1  |  at [Source: (org.jboss.resteasy.client.jaxrs.internal.ClientResponse$InputStreamWrapper); line: 1, column: 18] (through reference chain: org.keycloak.representations.AccessTokenResponse["access_token"])
docker-jboss-1  |       at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:138)
docker-jboss-1  |       at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:60)
docker-jboss-1  |       at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
docker-jboss-1  |       at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
docker-jboss-1  |       at com.sun.proxy.$Proxy519.grantToken(Unknown Source)
docker-jboss-1  |       at org.keycloak.admin.client.token.TokenManager.grantToken(TokenManager.java:99)
docker-jboss-1  |       at org.keycloak.admin.client.token.TokenManager.getAccessToken(TokenManager.java:75)

Here is my pom.xml :

    <properties>
            <jackson-version>2.13.3</jackson-version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>7.0</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-jaxrs</artifactId>
                <version>3.0.26.Final-redhat-1</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-cdi</artifactId>
                <version>3.0.26.Final-redhat-1</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-multipart-provider</artifactId>
                <version>3.0.26.Final-redhat-1</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-cache-core</artifactId>
                <version>3.1.4.Final</version>
            </dependency>
    <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.jaxrs</groupId>
                <artifactId>jackson-jaxrs-base</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.jaxrs</groupId>
                <artifactId>jackson-jaxrs-json-provider</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.module</groupId>
                <artifactId>jackson-module-jaxb-annotations</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.fasterxml.jackson.datatype</groupId>
                <artifactId>jackson-datatype-jsr310</artifactId>
                <version>${jackson-version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.jboss.resteasy</groupId>
                <artifactId>resteasy-jackson2-provider</artifactId>
                <version>3.0.26.Final-redhat-1</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.fasterxml.jackson.jaxrs</groupId>
                        <artifactId>jackson-jaxrs-json-provider</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    <dependency>
                <groupId>org.keycloak</groupId>
                <artifactId>keycloak-core</artifactId>
                <version>20.0.5</version>
            </dependency>
            <dependency>
                <groupId>org.keycloak</groupId>
                <artifactId>keycloak-adapter-core</artifactId>
                <version>20.0.5</version>
            </dependency>
<dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-admin-client</artifactId>
            <version>20.0.5</version>
        </dependency>

And the jboss-deployment-structure we use (we exclude some modules to be able to use a newer version of jackson - need for openapi) :

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <system export="true">
                <paths>
                    <path name="sun/reflect"/>
                </paths>
            </system>
        </dependencies>
        <exclusions>
            <module name="org.dom4j"/>
            <module name="com.fasterxml.jackson.core.jackson-core"/>
            <module name="com.fasterxml.jackson.core.jackson-annotations"/>
            <module name="com.fasterxml.jackson.core.jackson-databind"/>
            <module name="com.fasterxml.jackson.datatype.jackson-datatype-jdk8"/>
            <module name="com.fasterxml.jackson.datatype.jackson-datatype-jsr310"/>
            <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
            <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
            <module name="org.jboss.resteasy.resteasy-jackson-provider"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

I've tried a lot of things.. Changing the versions, exclude dependencies.. but nothing works :(

Could someone help me ?

Thank you


Solution

  • Well, I finally found something that works (but still don't understand why it doesn't work like that).. Here is my solution for now :

    First, I've extended de NamingBase to be able to override de names of the fields :

    public class CustomNaming extends PropertyNamingStrategies.NamingBase {
    
        public CustomNaming() {
            super();
        }
    
    
        @Override
        public String translate(String s) {
            switch (s) {
                case "token":
                    return "access_token";
                case "expiresIn":
                    return "expires_in";
                case "refreshExpiresIn":
                    return "refresh_expires_in";
                case "refreshToken":
                    return "refreshToken";
                case "tokenType":
                    return "token_type";
                case "idToken":
                    return "id_token";
                case "notBeforePolicy":
                    return "not-before-policy";
                case "sessionState":
                    return "session_state";
                case "errorDescription":
                    return "error_description";
                case "errorUri":
                    return "error_uri";
                default:
                    return s;
            }
        }
    }
    

    Then, I've also extended de ResteasyJackson2Provider to use that customNaming and other properties in the objectMapper :

    public class CustomRestEasyJackson2Provider extends ResteasyJackson2Provider {
    
        public CustomRestEasyJackson2Provider() {
            super();
            ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(new JavaTimeModule());
            mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            mapper.setPropertyNamingStrategy(new CustomNaming());
            setMapper(mapper);
        }
    }
    

    And finally, I use it in the KeycloakBuilder :

    Keycloak keycloak = KeycloakBuilder.builder()
                        .serverUrl(keycloakUrlAuth)
                        .realm(keycloakRealm)
                        .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
                        .clientId(keycloakClientId)
                        .clientSecret(keycloakClientSecret)
                        .resteasyClient(new ResteasyClientBuilder()
                                .register(new CustomRestEasyJackson2Provider(), 1000)
                                .build())
                        .build();
    

    Like that, it works !