Reputation: 31
I am trying to setup o auth2 authentication in spring cloud gateway for my rest apis using keycloak. keyclcoak redirects my request to login page while passing access token as bearer token. In many places I found solution for this is to set bearer-only = true in keycloak adapter. where to set this while using spring-boot-starter-oauth2-client. I cannot use keycloak-spring-boot-starter to set this in application.yml
Thanks
Upvotes: 1
Views: 1468
Reputation: 36
I had the same question as you. Not having found an answer, I developed a filter with a light keycloak Client that calls the Endpoint instrospect of keycloak to validate the token
the client:
public class KeycloakClient {
private final KeycloakConfigurationProperties kcProperties;
private final WebClient client;
public KeycloakClient(final KeycloakConfigurationProperties keycloakConfigurationProperties) {
this.kcProperties = keycloakConfigurationProperties;
this.client = WebClient.builder()
.baseUrl(keycloakConfigurationProperties.getAuth_server_url())
.filter(logRequest())
.build();
}
public Mono<Boolean> validateBearerToken(String bearerToken) {
//todo: improve error management
return prepareAndRunRequest(bearerToken).retrieve()
.bodyToMono(KeycloakValidationResponse.class)
.flatMap(response -> Mono.just(response.getActive()))
.onErrorResume(WebClientResponseException.class,
ex -> Mono.just(false));
}
private WebClient.RequestHeadersSpec<?> prepareAndRunRequest(String bearerToken) {
return client.post()
.uri(uriBuilder -> uriBuilder.path("/auth/realms/")
.path(kcProperties.getRealm())
.path("/protocol/openid-connect/token/introspect")
.build())
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromFormData("client_id", kcProperties.getResource())
.with("client_secret", kcProperties.getCredentials_secret())
the filter:
public class ValidationTokenGatewayFilterFactory extends AbstractGatewayFilterFactory<ValidationTokenGatewayFilterFactory.Config> {
private final KeycloakClient client;
public ValidationTokenGatewayFilterFactory(KeycloakClient client) {
super(Config.class);
this.client = client;
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String token = exchange.getRequest()
.getHeaders()
.get(AUTHORIZATION)
.get(0);
token = token.substring(7);
log.trace("-- ValidationToken(): token={}", token);
return client.validateBearerToken(token)
.flatMap(validated -> {
if (validated) {
log.debug("-- ValidationToken(): Token valid");
return chain.filter(exchange);
} else {
log.debug("-- ValidationToken(): Token invalid");
exchange.getResponse()
.setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse()
.setComplete();
}
});
};
}
public static class Config {
}
}
You can find a full sample here: https://gitlab.com/-/snippets/2105967
Upvotes: 1