Keycloak with Google login and role based access not working

66 views Asked by At

I have a Spring Boot application using keycloak, I'm giving the option to the user to login via google, right now the user is able to login via google and the token is being generated, but when I check the JWT I don't get the roles that I set to the user and in my Spring Boot application, the user is unable to access routes that must have user or admin permission. My goal is to create a user and admin role and make routes that can only be accessed if the user have such roles, I also want all user to have the role user by default and the admin role will need to be set manually.

I have tried a few different ways to create the roles but none worked. I'm not sure if I'm creating the roles wrong or there is another step to add when doing identity provider role based access. I appreaciate any help!

Create the role in the client: enter image description here

Tried to create realm roles: enter image description here

Tried to make composite roles of both client and realm roles: enter image description here

Tried to add a mapper to the identity provider: enter image description here

And last I tried to add the role directly to the user: enter image description here

Spring Boot application:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(
            authorizeConfig -> {
              authorizeConfig.requestMatchers("/public").permitAll();
              authorizeConfig.requestMatchers("/logout").permitAll();
              authorizeConfig.requestMatchers("/admin").hasRole("admin");
              authorizeConfig.requestMatchers("/usuario").hasRole("user");
              authorizeConfig.anyRequest().authenticated();
            })
        .oauth2Login(Customizer.withDefaults())
        .oauth2ResourceServer(config -> {
          config.jwt(Customizer.withDefaults());
        })
        .build();
  }
}

My application.yml:

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: my-keycloak-client-id
            client-secret: my-keycloak-client-secret
            scope: openid,profile,email
            
        provider:
          keycloak:
            user-name-attribute: preferred_username
            issuer-uri: http://localhost:8180/realms/google-teste
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8180/realms/google-teste

My Jwt (I've hidden sensitive information)

{
  "iat": 1712089584,
  "auth_time": 1712089583,
  "jti": "REDACTED",
  "iss": "http://localhost:8180/realms/google-teste",
  "aud": "spring-security-keycloak",
  "sub": "REDACTED",
  "typ": "ID",
  "azp": "spring-security-keycloak",
  "nonce": "REDACTED",
  "session_state": "REDACTED",
  "at_hash": "REDACTED",
  "acr": "1",
  "sid": "REDACTED",
  "email_verified": false,
  "name": "REDACTED",
  "preferred_username": "REDACTED",
  "given_name": "REDACTED",
  "family_name": "REDACTED",
  "email": "REDACTED",
  "realm_access": {
    "roles": [
      "offline_access",
      "default-roles-google-teste",
      "uma_authorization"
    ]
  },
}

The route to access the jwt token

@GetMapping("/cookie")
    String cookie(@AuthenticationPrincipal OidcUser principal) {
        return String.format("""
                    <h1>Oauth2   </h1>
                <h3>Principal: %s</h3>
                <h3>Email attribute: %s</h3>
                <h3>Authorities: %s</h3>
                <h3>JWT: %s</h3>
                """, principal, principal.getAttribute("email"), principal.getAuthorities(),
                principal.getIdToken().getTokenValue());
    }

Versions:

Keycloak: 24.0.2
Spring Boot: 3.1.5

1

There are 1 answers

1
Guenther Mahr On

The token will include the roles under a claim "realm_access" or "groups". You have to map them to authorities starting with ROLE_ like explained at https://www.baeldung.com/spring-boot-keycloak: in short you have to create a GrantedAuthoritiesMapper bean at startup which will then be used when a request is validated in Spring Security.

And another small detail not to forget: set the scope "microprofile-jwt" in the Keycloak client to "default".