Keycloak authentication and authorization between two microservices (server-to-server)

To make a microservice (ms-A) authenticated and authorized to make a request to another microservice (ms-B) secured with kc you have to properly configure spring security configuration on ms-B.
You can choose to had one or more authorities to a specific path (code 1) or leave all as is and authorize only your endpoint (code 2)

Code 1 - Spring Security

.antMatchers("/api/**").hasAuthority(“myRole-admin”)

Code 2
Spring Security:

.antMatchers("/api/**").authenticated()

Rest Controller:

@PreAuthorize(“hasAuthority(‘myRole-admin’)”)

Once ms-B is configured you have to do just a couple of changes into ms-A
First of all import these maven dependencies:

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client</artifactId>
    <version>${keycloak-admin-client.version}</version>
</dependency>
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-client</artifactId>
    <version>${resteasy-client.version}</version>
</dependency>
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jackson2-provider</artifactId>
    <version>${resteasy-client.version}</version>
</dependency>
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-multipart-provider</artifactId>
    <version>${resteasy-client.version}</version>
</dependency>

Tested dependencies version:

<keycloak-admin-client.version>6.0.1</keycloak-admin-client.version>
<resteasy-client.version>3.6.3.Final</resteasy-client.version>

Then before call the endpoint of ms-B you must create the keycloak object authenticated on ms-A’s client, retrieve the access token and it to request headers

Keycloak keycloak = KeycloakBuilder.builder()
    .serverUrl("https://my-keycloak-server/auth")
    .realm("my-keycloak-realm")
    .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
    .clientId("kc-ms-A-client-id")
    .clientSecret("kc-ms-A-client-secret")
    .build();

AccessTokenResponse accessToken = keycloak.tokenManager().getAccessToken();

once you have an access token you can add it to request headers for example using basic RestTemplate:

RestTemplate restTemplate = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.set(“Authorization”, "Bearer " + accessToken.getToken());
HttpEntity httpEntity = new HttpEntity(headers);

ResponseEntity response = restTemplate.exchange(
http://ms-B-endpoint/”,
HttpMethod.GET,
httpEntity,
String.class
);

The last important thing you have to do is assign the role of ms-B client to ms-A client Service Account on Keycloak

  • Open keycloak
  • Go to “Clients” and select ms-A client
  • Click on tab “Service Account Roles”
  • Choose from “Client Roles” list the ms-B client
  • Add the needed rolesPreformatted text
1 Like