Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java client to refresh keycloak token

Imagine,

Following are the 2 clients (2 micro-services) in keyclock.

  • rest-service-1
  • rest-service-2

Following is the role in rest-service-2

  • service-2-user

To do service to service call, ie: rest-service-1 calls rest-service-2

'rest-service-1' is configured with following values in Keycloak

Access Type: confidential
Service Account Enabled: Yes

Also, under 'Service Account Roles' for rest-service-1, following role is added/mapped

Role for client rest-service-2: service-2-user

After setting up the 2 clients and service account for calling client in keyclock. I created a Spring boot 2.0.3 project and used the following code to get the token.

@Bean
public AuthzClient authzClient(KeycloakSpringBootProperties kcProperties) {
  //org.keycloak.authorization.client.Configuration
  Configuration configuration =
      new Configuration(kcProperties.getAuthServerUrl(), 
                        kcProperties.getRealm(), 
                        kcProperties.getResource(),
                        kcProperties.getCredentials(), null);

  return AuthzClient.create(configuration);
}

Here is how I get access token

@Autowired
private AuthzClient authzClient;

public AccessTokenResponse token() {
  return authzClient.obtainAccessToken();
}

Following is the token received:

{
  "access_token": ${access-token},
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": ${refresh-token},
  "token_type": "bearer",
  "id_token": null,
  "not-before-policy": 0,
  "session_state": "6f284b2f-5bb6-4018-8acd-b83923ebb7d7",
  "scope": "profile email"
}

Note: I replaced tokens for making it short/brief.

QUESTION:

How do use the refresh token stated above and get a new Access Token. Does AuthzClient support that? If so, how do I do that?

Do I need to create a new Instance of TokenCallable and get the token? If so how to instanciate TokenCallable?

Is TokenCallable thread safe?

like image 205
Arun Chandrasekaran Avatar asked Jun 28 '18 21:06

Arun Chandrasekaran


1 Answers

You cannot do this explicitly by means of AuthzClient class. However, you can use some low-level API from org.keycloak.authorization.client.util package, i.e. the Http class. For example:

public AccessTokenResponse refreshToken(String refreshToken) {
    String url = kcProperties.getAuthServerUrl() + "/realms/" + kcProperties.getRealm() + "/protocol/openid-connect/token";
    String clientId = kcProperties.getResource();
    String secret = (String) kcProperties.getCredentials().get("secret");
    Http http = new Http(kcConfig, (params, headers) -> {});

    return http.<AccessTokenResponse>post(url)
            .authentication()
                .client()
            .form()
                .param("grant_type", "refresh_token")
                .param("refresh_token", refreshToken)
                .param("client_id", clientId)
                .param("client_secret", secret)
            .response()
                .json(AccessTokenResponse.class)
            .execute();
}

@Bean
public org.keycloak.authorization.client.Configuration kcConfig() {
    return new org.keycloak.authorization.client.Configuration(
            kcProperties.getAuthServerUrl(),
            kcProperties.getRealm(),
            kcProperties.getResource(),
            kcProperties.getCredentials(),
            null
    );
}

This solution is fully thread-safe (see CloseableHttpClient for the details).

like image 165
maslick Avatar answered Nov 11 '22 10:11

maslick