4

I'm trying to build an Angular 2 page on top of a Spring Boot API. I have configured CORS (correctly I believe), but I am getting blocked by Spring Security's CSRF protection.

It is my understanding that Angular 2 handles CSRF automatically as of RC2, and I am on RC4. The server is sending an XSRF token in response to a POST from the Client as seen here:

enter image description here

I assume that Angular 2 is not picking it up? I know that CORS is working because when I put .ignoringAntMatchers("/urlhere/") on the end of .csrf() to test, the request went through, so CORS is not blocking it. Here is my config method for HttpSecurity:

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

    http
        .authorizeRequests()
            .antMatchers("/auth/**", "/signup/**").permitAll()
            .and()
        .headers() 
            .and()
        .exceptionHandling()
            .and()
        .cors()
            .and()
        .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

}

My Login process on client side consists of a method that first sends credentials, then uses a JWT token to retrieve credentials. The two methods are as follows:

sendCredentials(model) {
   let tokenUrl = 'http://localhost:8080/user/login';
   let headers1 = new Headers({'Content-Type': 'application/json'});

   return this.http.post(tokenUrl, JSON.stringify(model), {headers: headers1});
}

sendToken(token){
   let userUrl = 'http://localhost:8080/rest/user/users';
   let headers2 = new Headers({'Authorization': 'Bearer '+token});

   return this.http.get(userUrl, {headers:headers2});
}

What am I missing to satisfy the requirements for CSRF protection? Is it client side? Or am I needing to add /login/ to my list of antMatchers?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
fun_hat
  • 547
  • 2
  • 7
  • 25

1 Answers1

3

I know it's late but, I ran into same problem and managed to solve it. Problem in angular http request:

return this.http.post(tokenUrl, JSON.stringify(model), {headers: headers1});

You need to adjust it to send like that :

return this.http.post(tokenUrl, JSON.stringify(model), {headers: headers1, withCredentials: true});

You have to add withCredentials: true to all your http requests. Why you need it? Each time you send http request(OPTIONS, POST etc) to Spring(server) it will generate new XSRF-TOKEN and issue it to client, withCredentials: true will save this new XSRF-TOKEN in browser and later on used for new http request, so in case one of your http requests doesn't have withCredentials: true it will simply ignore new XSRF-TOKEN and use old(expired) XSRF-TOKEN for http request.

Popeye
  • 339
  • 4
  • 14