I have a question about how to incorporate JWT tokens with CSRF protection when integrating with the Angular framework and Spring security 6. While there numerous posts on whether to use both CSRF and JWT, the intent is to seek advice on how to implement both and understand expected behavior. I have been following the SPRING DOCS here - https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript
The most common answer to this is to disable csrf because it is stateless but to some extent state is maintained by the front end UI.
My application is experiencing the following behavior and I do not know how to get around it.
What is the correct way to constantly refresh the csrf cookie?
The following are my project configurations
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
CsrfTokenRequestAttributeHandler crsfTokenRequestHandler = new CsrfTokenRequestAttributeHandler();
http
//.securityContext(contextConfig -> contextConfig.requireExplicitSave(false)) // removed and only used for JSESSIONID
.sessionManagement(sessionConfig-> sessionConfig.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.cors(corsConfig -> corsConfig.configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration myconfig = new CorsConfiguration();
myconfig.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
myconfig.setAllowedMethods(Collections.singletonList("*"));
myconfig.setAllowCredentials(true);
myconfig.setAllowedHeaders(Collections.singletonList("*"));
myconfig.setExposedHeaders(Arrays.asList("Authorization"));
myconfig.setMaxAge(3600L);
return myconfig;
}
}))
//.csrf(csrf -> csrf.disable())
.csrf(csrfConfig ->
csrfConfig.csrfTokenRequestHandler(crsfTokenRequestHandler)
.ignoringRequestMatchers(REGISTER_URL, H2_CONSOLE_URL)
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.addFilterAfter(new JWTTokenGeneratorFilter(), BasicAuthenticationFilter.class)
.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class)
.addFilterBefore(new JWTTokenValidationFilter(), BasicAuthenticationFilter.class)
.requiresChannel(rcc -> rcc.anyRequest().requiresInsecure())
.authorizeHttpRequests((requests) -> requests
.requestMatchers(H2_CONSOLE_URL).permitAll()
.requestMatchers(REGISTER_URL, "/error", "/invalidSession").permitAll()
.requestMatchers(LOGIN_URL,OCCASSIONS_LIST_URL, OCCASSION_GET, OCCASSIONS_EDIT, OCCASIONS_ADD, USER_GET, USER_EDIT).authenticated())
.headers(h -> h.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin));
//http.formLogin(flc -> flc.disable()); // this is a login page with a user name and password using Spring MVC
http.formLogin(withDefaults());
http.httpBasic(hbc -> hbc.authenticationEntryPoint(new CustomBasicAuthenticationEntryPoint())); // this is header based
http.exceptionHandling(ehc -> ehc.accessDeniedHandler(new CustomAccessDeniedHandler()));
return http.build();
}
The CSRF chapter you linked to has advice on disabling CSRF which in turn links to an explanation of when to use CSRF protection. That explanation is intended to help you understand why you should not disable CSRF in browser-based applications.
In terms of configuring your application for CSRF, the page you linked has all the advice you need and you just need to follow it closely. However, adding your own custom JWT filter is inadvisable and will potentially cause problems like the one you are seeing if it is implemented incorrectly. Please see the OAuth2 Resource Server overview, which contains a section explaining how to use a custom JWT if you must use one. You do not need to implement your own JWT support.
NOTE: You can easily build an OAuth2-based solution with Spring Authorization Server that would be more beneficial to learn than supporting custom JWTs. Your backend services (APIs) would continue to be "stateless" in the way most people think of it.
Regardless, when you enable JWT support that comes with Spring Security's OAuth2 Resource Server, you should continue following advice in the CSRF chapter and leave CSRF protection enabled. There are several options there for correctly integrating your frontend with CSRF.