Spring boot + Spring Security + Keycloak - can't understand how it all should work

Hey there! I am trying to use Keycloak with Spring security but i cannot get it to work correctly. For some reason it tries to authenticate every request, it calls KeycloakAuthenticationProcessingFilter even tho Spring security already has a populated Authentication object in SecurityContextHolder. I don’t know if that’s how it should work. Plus i can’t get it to log out, I always get this error: o.k.a.RefreshableKeycloakSecurityContext : failed to invoke remote logout
org.keycloak.adapters.ServerRequest$HttpFailure: null

here’s my application.properties:

keycloak.realm=realm
keycloak.resource=client
keycloak.public-client=true
keycloak.ssl-required=external
keycloak.cors=true
keycloak.enabled=true
keycloak.bearer-only=false
keycloak.enable-basic-auth=true
keycloak.principal-attribute=preferred_username
client-secret={client_secret}

and here's my configuration class:

@Configuration
@KeycloakConfiguration
@EnableWebSecurity
public class KeyCloakConfig extends KeycloakWebSecurityConfigurerAdapter {

  @Autowired
  public void configureGlobal(
      AuthenticationManagerBuilder auth) {
    KeycloakAuthenticationProvider keycloakAuthenticationProvider
        = keycloakAuthenticationProvider();
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
        new SimpleAuthorityMapper());
    auth.authenticationProvider(keycloakAuthenticationProvider);
  }

  @Bean
  @Override
  protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    return new RegisterSessionAuthenticationStrategy(sessionRegistry());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
    http
        .cors()
        .and()
        .csrf()
        .disable()
        .authorizeRequests()
        .antMatchers("/v2/api-docs",
            "/configuration/ui",
            "/configuration/security",
            "/swagger-ui.html",
            "/swagger-resources",
            "/swagger-resources/configuration/ui",
            "/swagger-resources/configuration/security",
            "/webjars/**").permitAll()
        .antMatchers("/models/**", "/user")
        .authenticated()
        .and()
        .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
  }
}
  @Bean
  public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
    return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
  }

  @Bean
  public SessionRegistry sessionRegistry() {
    return new SessionRegistryImpl();
  }

  @Bean
  @Override
  @ConditionalOnMissingBean(HttpSessionManager.class)
  protected HttpSessionManager httpSessionManager() {
    return new HttpSessionManager();
  }

  @Bean
  @Override
  protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
    RequestMatcher requestMatcher =
        new OrRequestMatcher(
            new AntPathRequestMatcher("/sso/login"),
            new QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN),
            new IgnoreKeycloakProcessingFilterRequestMatcher());
    return new KeycloakAuthenticationProcessingFilter(authenticationManagerBean(), requestMatcher);
  }

  private static class IgnoreKeycloakProcessingFilterRequestMatcher implements RequestMatcher {

    public boolean matches(HttpServletRequest request) {
      String authorizationHeaderValue = request.getHeader("Authorization");
      return authorizationHeaderValue != null && !authorizationHeaderValue.startsWith("Basic ");
    }
  }
}


and this is how i get user token through openid:

private TokenDto getToken(String username, String password, String clientId, String realm) {
    String tokenUri = cloakUri + "/realms/" + realm + "/protocol/openid-connect/token";
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("password", password);
    map.add("username", username);
    map.add("grant_type", "password");
    map.add("client_id", clientId);
    map.add("client_secret", clientSecret);
    map.add("scope", "openid");
    HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
    ResponseEntity<Token> response = restTemplate.exchange(tokenUri, HttpMethod.POST, entity, Token.class);
    if (response.getBody() != null) {
      return new TokenDto(response.getBody().getAccessToken());
    }
    return null;
  }

Hello, Did you get any solution for this ?

See:

Hi, I have 2 projects with Spring Boot and Keycloak

Maybe, they can help. Best