CSRF issue while sending POST request from Angular 2 to Spring-backed Java app

Viewed 2801

I have UI written with Angular 2 and Java based backend that uses OpenID Connect authentication on top of Spring Security.

The authentication works fine but only for GET requests. I'm getting HTTP 403 every time I perform POST, PUT or DELETE methods on a resource:

{
  "status": 403,
  "message": "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.",
}

I use HttpClient like this:

http.post(
    '/api/my-resource',
    JSON.stringify(myObject),
    new RequestOptions({
        headers: new Headers({'Content-Type': 'application/json'})
    })
)

When I add withCredentials: true to the RequestOptions as proposed here I still get HTTP 403 but with different message:

{
  "status": 403,
  "message": "Could not verify the provided CSRF token because your session was not found.",
}

What do I need to do to make HttpClient work with CSRF?

Note: I also took a look at similar questions, especially angular-2-spring-security-csrf-implementation-problems, but the solutions proposed there do not solve my problem. At the same time I don't want to disable CSRF.

2 Answers

With spring-boot 2.2.2 (spring-security 5.2.1) and Angular 8.2.14, this configuration works for me:

  @NgModule({
  declarations: [],
  imports: [
    BrowserModule,
    HttpClientModule,
    HttpClientXsrfModule.withOptions({cookieName: 'XSRF-TOKEN'}),

The same configuration as the updated response of Radouane.

But for the springboot part:

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.csrf()
         .csrfTokenRepository(cookieCsrfTokenRepository())
         .and()
         .authorizeRequests()
         .antMatchers("/static/**").permitAll()
         ...
         .anyRequest().authenticated();
}

private CookieCsrfTokenRepository cookieCsrfTokenRepository() {

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

According to this answer,

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

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

Related