Angular 6 does not add X-XSRF-TOKEN header to http request

58.3k Views Asked by At

I've read the docs and all the related questions on SO, but still Angular's XSRF mechanism isn't working for me: in no way I can make a POST request with the X-XSRF-TOKEN header appended automatically.

I have an Angular 6 app with a login form.

It's part of a Symfony (PHP 7.1) website, and the Angular app page, when served from Symfony, sends the correct Cookie (XSRF-TOKEN):

enter image description here

My app.module.ts includes the right modules:

// other imports...
import {HttpClientModule, HttpClientXsrfModule} from "@angular/common/http";

// ...
@NgModule({
  declarations: [
    // ...
  ],
  imports: [
    NgbModule.forRoot(),
    BrowserModule,
    // ...
    HttpClientModule,
    HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-CSRF-TOKEN'
    }),
    // other imports
  ],
  providers: [],
  entryComponents: [WarningDialog],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Then, inside a Service's method, I'm making the following http request (this.http is an instance of HttpClient):

this.http
    .post<any>('api/login', {'_username': username, '_pass': password})
    .subscribe(/* handler here */);

The post request never sends the X-XSRF-TOKEN header. Why?

8

There are 8 best solutions below

10
On BEST ANSWER

The problem once again is Angular's poor documentation.

The fact is, Angular will add the X-XSRF-TOKEN header only if the XSRF-TOKEN cookie was generated server-side with the following options:

  • Path = /
  • httpOnly = false (this is very important, and fully undocumented)

Besides, the Angular app and the URL being called must reside on the same server.

Refer this Angular Github issue

0
On

Make sure, your server allows X-CSRF-Token headers on when browser requests OPTIONS method.

Example:

Access-Control-Allow-Headers: X-CSRF-Token, Content-Type

Reference: MDN Docs

2
On

After struggling for countless hours, the solution that worked for us was changing the request (in Angular) from 'https://example.com' to '//example.com'.

None of the other solutions worked for us.

0
On
    request = request.clone({
        withCredentials: true
      });

In InterceptService, this works with me

1
On

For Spring Boot users this below taken me a while:

Besides, the Angular app and the URL being called must reside on the same server.

I was testing my solution on my localhost with apps on different ports and it works like it was the same origin.

But the problem happened after I changed context-path: /api and this was different from origin thats why I suppose Angular won't add XSRF token to request, so I need to add:

final CookieCsrfTokenRepository cookieCsrfTokenRepository =  CookieCsrfTokenRepository.withHttpOnlyFalse();
    cookieCsrfTokenRepository.setCookiePath("/");

to set up them same origin

Here is complex solution for diffrent context-path

0
On

You should put on the service on the frontend this { withCredentials: true }

Ex:

this.http.put<class>(url, body, { withCredentials: true });
0
On

Slightly off topic, but for others who come here, I resolved this issue in the back end by the following (for spring-boot)

     /**
     * CORS config - used by cors() in configure() DO NOT CHANGE the METDHO NAME
     * 
     * @return
     */
    @Bean()
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Lists.newArrayList("http://localhost:4200"));
        configuration.setAllowedMethods(Lists.newArrayList("GET", "POST", "OPTIONS"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Lists.newArrayList("x-xsrf-token", "XSRF-TOKEN"));
        configuration.setMaxAge(10l);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
3
On

On my team, the problem was that we were using an absolute path instead of a relative path.

So do not use an absolute path like:

this.http.post<any>("https://example.com/api/endpoint",data)

Use

this.http.post<any>("api/endpoint",data)

Or use

this.http.post<any>("//example.com/api/endpoint",data)

This is because absolute paths are explicitly ignored by Angular code on HttpClientXsrfModule (see)