Issue
Im trying to build a spring gateway which is getting JWT and is sending the tokens to all underlying services. For this I use the following dependencies:
<!-- Spring Boot Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<!-- Spring Boot Dependencies -->
<!-- Spring Cloud Dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Spring Cloud Dependencies -->
I configured my application for Auth0:
spring:
cloud:
gateway:
routes:
- id: my-service
uri: http://localhost:8001/
predicates:
- Path=/comments
filters:
- TokenRelay= #to send the token to the underlying service
- RemoveRequestHeader=Cookie #remove cookies since underlying services don't need them
security:
oauth2:
resourceserver:
jwt:
issuer-uri: #my issuer-uri
audience: #my audience
I implemented the audience validator and the jwt decoder like described here:
@Configuration
@ConditionalOnProperty(name = {"spring.security.oauth2.resourceserver.jwt.issuer-uri"})
public class AuthenticationOauth2Configuration {
@Value("${spring.security.oauth2.resourceserver.jwt.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
@Bean(name = "customJwtDecoder")
public JwtDecoder getJwtDecoder() {
final NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
final OAuth2TokenValidator<Jwt> audienceValidator = new JwtAudienceValidator(audience);
final OAuth2TokenValidator<Jwt> issuer = JwtValidators.createDefaultWithIssuer(this.issuer);
final OAuth2TokenValidator<Jwt> audience = new DelegatingOAuth2TokenValidator<>(issuer, audienceValidator);
jwtDecoder.setJwtValidator(audience);
return jwtDecoder;
}
}
public class JwtAudienceValidator implements OAuth2TokenValidator<Jwt> {
private final String audience;
public JwtAudienceValidator(final String audience) {
this.audience = audience;
}
@Override
public OAuth2TokenValidatorResult validate(Jwt jwt) {
final OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
if (jwt.getAudience().contains(audience)) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(error);
}
}
However when Im starting the gateway service im getting the following error:
Caused by: reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name TokenRelay
Caused by: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name TokenRelay
I literally cant find any resources on how to fix this.
Solution
You need org.springframework.boot:spring-boot-starter-oauth2-client as said here. But I don't think you need it as soon as you use resource server. Gateway will forward your headers downstream without any configuration, so you will be able to find the authorization header there.
Answered By - Eduard Khachirov