Reputation: 1
I'm working with Spring Boot and Okta OAuth2 client integration using WebFlux. After configuring my dependencies and application properties, I encounter an issue with the JWT token validation. Specifically, I get an error where the JOSE header type application/okta-internal-at+jwt is not allowed.
The exception details are as follows: I have already tried to configure a custom ReactiveJwtDecoder with a custom token validator to handle Okta internal tokens. However, the validation fails due to the unsupported typ header in the JWT token (application/okta-internal-at+jwt). My expectation was that the custom validator would allow the token to pass, but it didn't.
pom.xml
Spring Boot Version <version>3.4.1</version>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
Application Properties Configuraataions
# Octa Security
spring.security.oauth2.client.registration.okta.client-id=0oan0wkeiuzfUuHsw5d7
spring.security.oauth2.client.registration.okta.client-secret=uHLcvr9G8jT69Lmbxb_PoHJ7ltPeE5zd4PphpxrwNvD41gP7vHALXdF7CMMjdhr2
spring.security.oauth2.client.registration.okta.scope=openid, profile, email, offline_access
spring.security.oauth2.client.registration.okta.provider=okta
spring.security.oauth2.client.provider.okta.issuer-uri=https://dev-52900394.okta.com
spring.security.oauth2.client.registration.okta.redirect-uri=http://localhost:8093/login/oauth2/code/okta
SecurityConfig
package com.gateway.ApiGateway.security;
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
httpSecurity
.authorizeExchange(exchanges -> exchanges
.anyExchange()
.authenticated()
)
.oauth2Login()
.and()
.oauth2ResourceServer()
.jwt();
return httpSecurity.build();
}
@Bean
public ReactiveJwtDecoder jwtDecoder() {
NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder
.withJwkSetUri("https://dev-52900394.okta.com/oauth2/v1/keys")
.build();
// Custom JWT validator to allow Okta internal tokens
OAuth2TokenValidator<Jwt> customValidator = jwt -> {
String tokenType = (String) jwt.getHeaders().get("typ");
if (!"application/okta-internal-at+jwt".equals(tokenType) && !"JWT".equals(tokenType)) {
throw new JwtValidationException("Invalid token type", null);
}
// Apply default validators (expiry, signature, etc.)
return JwtValidators.createDefault().validate(jwt);
};
jwtDecoder.setJwtValidator(customValidator);
return jwtDecoder;
}
@Bean
public ReactiveJwtAuthenticationConverter jwtAuthenticationConverter() {
ReactiveJwtAuthenticationConverter converter = new ReactiveJwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
List<GrantedAuthority> authorities = ((List<String>) jwt.getClaims().getOrDefault("roles", List.of()))
.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return Flux.fromIterable(authorities);
});
return converter;
}
}
I trid below curl in postman
curl --location 'http://172.17.80.1:8093/questions' \
--header 'Authorization: Bearer eyJraWQiOiJaWTdvNEk5YWpMSmtQeENJNTFEVVJaQ1NvaEEtZjNKdFNDOWtLd1pva2ZnIiwidHlwIjoiYXBwbGljYXRpb25cL29rdGEtaW50ZXJuYWwtYXQrand0IiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULm5UTDRlRUxBc1RPRUVqZ21HMFlRc2NFdEQwbUlveXdhbDRzeXd4ODJWWTgub2FyMndybTE3ZEFYdllkdHA1ZDciLCJpc3MiOiJodHRwczovL2Rldi01MjkwMDM5NC5va3RhLmNvbSIsImF1ZCI6Imh0dHBzOi8vZGV2LTUyOTAwMzk0Lm9rdGEuY29tIiwic3ViIjoicmF2aWRvYmFyaXlhOTUzN0BnbWFpLmNvbSIsImlhdCI6MTczODIxODc4NiwiZXhwIjoxNzM4MjIyMzg2LCJjaWQiOiIwb2FuMHdrZWl1emZVdUhzdzVkNyIsInVpZCI6IjAwdW4wd202NTRrb3NZRm5mNWQ3Iiwic2NwIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJlbWFpbCIsIm9mZmxpbmVfYWNjZXNzIl0sImF1dGhfdGltZSI6MTczODIxODc4Mn0.m4VJTDqpCl64PbE9dGYtzKokrU7Gf82UHfbPcroyVx4bO_psuLAjgzIinbqhbuiVRfHlN-nLGLS7jzSwY6Gib5uE1Fo-ioxkq1TUs7_bOYOI82O2XMoIe8H970FeMqprSZVdXYPMfEx5JlFdGSbl6rkQ6OG9QRRfkCk-GeZpG5O5BzE1eb9vMwO09oHntKaruv0OQJrIFu2lK1wxtfVcSBkM7xeTAWqrCQmHmuEjrj58PJFXU0Ci5RZgX6Yipp5LS0IhR7YnDmowy64PPkc9D1hOOJDxuDivT_X7-OcLhOZbH4bOhegr52va79nmMxquJlOsnE56xNCcCLA72xo6Aw' \
--header 'Cookie: SESSION=928008dd-57a2-470a-9565-13e606aaeb5d'
I got below exception
org.springframework.security.oauth2.server.resource.InvalidBearerTokenException: Failed to validate the token
at org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager.onError(JwtReactiveAuthenticationManager.java:79) ~[spring-security-oauth2-resource-server-6.4.2.jar:6.4.2]
at reactor.core.publisher.Mono.lambda$onErrorMap$28(Mono.java:3848) ~[reactor-core-3.7.1.jar:3.7.1]
at reactor.core.publisher.Mono.lambda$onErrorResume$30(Mono.java:3938) ~[reactor-core-3.7.1.jar:3.7.1]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.7.1.jar:3.7.1]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.116.Final.jar:4.1.116.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.116.Final.jar:4.1.116.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.116.Final.jar:4.1.116.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.116.Final.jar:4.1.116.Final]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: org.springframework.security.oauth2.jwt.BadJwtException: Failed to validate the token
at org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.createClaimsSet(NimbusReactiveJwtDecoder.java:295) ~[spring-security-oauth2-jose-6.4.2.jar:6.4.2]
at org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder$JwkSetUriReactiveJwtDecoderBuilder.lambda$processor$13(NimbusReactiveJwtDecoder.java:449) ~[spring-security-oauth2-jose-6.4.2.jar:6.4.2]
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:106) ~[reactor-core-3.7.1.jar:3.7.1]
... 232 common frames omitted
Caused by: com.nimbusds.jose.proc.BadJOSEException: JOSE header typ (type) application/okta-internal-at+jwt not allowed
at com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier.verify(DefaultJOSEObjectTypeVerifier.java:149) ~[nimbus-jose-jwt-9.37.3.jar:9.37.3]
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:341) ~[nimbus-jose-jwt-9.37.3.jar:9.37.3]
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:303) ~[nimbus-jose-jwt-9.37.3.jar:9.37.3]
at org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.createClaimsSet(NimbusReactiveJwtDecoder.java:292) ~[spring-security-oauth2-jose-6.4.2.jar:6.4.2]
... 234 common frames omitted
Upvotes: 0
Views: 11