Describe the bug I have configured JWT authentication using spring boot with 'BearerTokenAuthenticationEntryPoint' to handle exceptions for unauthorized requests. CORS is also configured on the app.
When a requests is performed without a JWT token the 'BearerTokenAuthenticationEntryPoint' handles the error and returns a 401 UNAUTHORIZED status.
The problem is that it does not add any 'Access-Control-Allow-Origin' header causing a CORS error on the frontend.
To Reproduce Use the following web configuration and perform a request to any secured controller. You will receive a CORS error instead of just a 401 status code.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebConfiguration implements WebMvcConfigurer {
@Value("${public.key}")
RSAPublicKey key;
@Value("${private.key}")
RSAPrivateKey priv;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedOrigins("http://localhost:4200")
.allowedHeaders("*")
.allowCredentials(true);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
// @formatter:on
.csrf((csrf) -> csrf.ignoringAntMatchers(new String[] {}))
// Add jwt authentication with stateless session (HttpSession will not be used
// to get user data)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
.accessDeniedHandler(new BearerTokenAccessDeniedHandler()));
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(this.key).build();
}
@Bean
JwtEncoder jwtEncoder() {
JWK jwk = new RSAKey.Builder(this.key).privateKey(this.priv).build();
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}
}
Expected behavior 'BearerTokenAuthenticationEntryPoint' should add CORS header if CORS has been configured.
Sample spring-api.zip
Comment From: sjohnr
@huco95, thanks for the reaching out and providing a detailed example.
It looks as though you are not allowing a pre-flight request with Spring Security. This is done by calling http.cors(). See the CORS chapter of the reference. Have you tried this?
The problem is that it does not add any 'Access-Control-Allow-Origin' header causing a CORS error on the frontend.
I believe this header should be returned on the OPTIONS request, not a normal request to the resource server. In my testing, adding http.cors() to the security configuration resolves the issue. Please let me know if that solves it for you, or if I'm misunderstanding something in your setup.
Comment From: huco95
Hi @sjohnr
You were right, http.cors() was missing and that's why I have the CORS error.
Thanks!!