Angular does not set X-XSRF-TOKEN

182 Views Asked by At

I am using Angular 17 and Spring Boot with Spring Security 6.

As it states in Angular documentation, when performing HTTP requests, an interceptor reads a token from a cookie, by default XSRF-TOKEN, and sets it as an HTTP header, X-XSRF-TOKEN. For this, in Angular I added

importProvidersFrom([
  HttpClientXsrfModule.withOptions({
    cookieName: "XSRF-TOKEN",
    headerName: "X-XSRF-TOKEN",
  }),
]),

Now taking a look at Spring documentation I can construct this configuration for CSRF:

@Bean
fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain {
    val tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()
    tokenRepository.cookiePath = "/"

    val delegate = XorCsrfTokenRequestAttributeHandler()
    delegate.setCsrfRequestAttributeName("_csrf")

    val requestHandler = CsrfTokenRequestHandler(delegate::handle)

    return httpSecurity
        .csrf { configurer ->
            configurer
                .csrfTokenRepository(tokenRepository)
                .csrfTokenRequestHandler(requestHandler)
        }
        .cors(Customizer.withDefaults<CorsConfigurer<HttpSecurity>>())
        <...>

Also, CorsMapping, where Angular runs on localhost:4200 port:

override fun addCorsMappings(registry: CorsRegistry) {
    registry
        .addMapping("/**")
        .allowedOrigins("http://localhost:4200")
        .allowedMethods("GET", "POST", "PUT", "DELETE")
        .allowedHeaders("Content-Type", "X-XSRF-TOKEN")
        .allowCredentials(true)
}

When trying to perform login:

enter image description here

I tried removing http:// part from the request, but then Angular requests show:

enter image description here

When I perform login via Postman, everything works on first attempt - I get newly set XSRF-TOKEN in a cookie and X-XSRF-TOKEN in a header.

What am I missing here? Thanks.

1

There are 1 best solutions below

2
FabianGuarascio On

In Angular you need to add an option { withCredentials: true } to the http call you do to the backend. This is for sending cookies ( outgoing credentials) in the request.

it would look like something like this

login(){
  const paylaod = {username:'admin', password:'1234'}
  const url = 'http://localhost:8080/auth/login'
  return this.http.post( url, payload, { withCredentials: true } )
}

For security reasons Angular by default dosent let you send the credentials without you explicity tell the http client to send the credentials.

(if your spring aplication has more endpoints that need those credentials , in angular you need to put whithCredentials: true to all the http calls you make to send to the backend those credentials)