Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OAuth2 client credentials flow via Spring Boot Keycloak integration

My application consists of:

  • backend/resource server
  • UI webapp
  • keycloak

The UI is talking with the backend server via RESTful API using the keycloak client with authorization code grant flow. This is working fine.

Now, I need the additional possibility to access resource of the backend using a system/service account (with usually more permissions than the user). How would you implement this requirement? I thought the client credentials flow would be useful here.

Is it possible to use the OAuth2 client credentials flow with the keycloak client for Spring Boot? I found examples that used the Spring Security OAuth2 client features to achieve a client credentials flow but that feels weird because I already use the keycloak client for the OAuth thing.

Edit: Solution

Thanks for your answers which helped me a lot. In my UI webapp, I am now able to communicate with the backend either by using the authenticated user OAuth2 token or by using the token from the client credentials flow of my UI service account. Each way has its own RestTemplate, the first is done via the keycloak integration and second is done by Spring Security OAuth2 as explained here.

like image 633
Steffen Harbich Avatar asked Sep 17 '19 12:09

Steffen Harbich


1 Answers

Yes, you can use OAuth 2.0 Client Credentials flow and Service Accounts.

Keycloak suggest 3 ways to secure SpringBoot REST services:

  1. with Keycloak Spring Boot Adapter
  2. with keycloak Spring Security Adapter
  3. with OAuth2 / OpenID Connect

Here is a good explanation about this with an example in the OAuth2/OIDC way:

  • Tutorial by Arun B Chandrasekaran
  • Code sample by Arun B Chandrasekaran

If you follow this example, keep in mind:

Take care to configure your client as:

  • Access Type: Confidential
  • Authorization: Enabled
  • Service Account (OAuth Client Credentials Flow): Enabled

Take care to configure your target service as:

  • Access Type: Bearer-only

So, caller should be confidential and target service should be bearer-only.

Create your users, roles, mappers... and assign roles to your users.

Check that you have this dependencies in your spring project:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>

Configure authentication to be used in the REST client (application.properties) e.g.:

security.oauth2.client.client-id=employee-service
security.oauth2.client.client-secret=68977d81-c59b-49aa-aada-58da9a43a850
security.oauth2.client.user-authorization-uri=${rest.security.issuer-uri}/protocol/openid-connect/auth
security.oauth2.client.access-token-uri=${rest.security.issuer-uri}/protocol/openid-connect/token
security.oauth2.client.scope=openid
security.oauth2.client.grant-type=client_credentials

Implement your JwtAccessTokenCustomizer and SecurityConfigurer (ResourceServerConfigurerAdapter) like Arun's sample.

And finally implement your service Controller:

@RestController
@RequestMapping("/api/v1/employees")
public class EmployeeRestController {

  @GetMapping(path = "/username")
  @PreAuthorize("hasAnyAuthority('ROLE_USER')")
  public ResponseEntity<String> getAuthorizedUserName() {
    return ResponseEntity.ok(SecurityContextUtils.getUserName());
  }

  @GetMapping(path = "/roles")
  @PreAuthorize("hasAnyAuthority('ROLE_USER')")
  public ResponseEntity<Set<String>> getAuthorizedUserRoles() {
    return ResponseEntity.ok(SecurityContextUtils.getUserRoles());
  }
}

For a complete tutorial, please read the referred Arun's tutorial.

Hope it helps.

like image 176
Ariel Carrera Avatar answered Sep 21 '22 18:09

Ariel Carrera