0

I've got a Spring boot RESTful service with Spring security configured like so:

protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.cors().and()
                /*.formLogin().loginPage("/auth")
                .permitAll().and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and().httpBasic().and()*/
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
    }

&

public class CsrfHeaderFilter extends OncePerRequestFilter {

private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (csrf != null) {
        response.addHeader("X-CSRF-TOKEN", csrf.getToken());
        Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
        String token = csrf.getToken();

        if (cookie == null || token != null && !token.equals(cookie.getValue())) {
            cookie = new Cookie(CSRF_COOKIE_NAME, token);
            cookie.setPath("/");
            response.addCookie(cookie);
        }
    }

    filterChain.doFilter(request, response);
}

}

I'm invoking the RESTful service using Angular 4 (latest version). It's doing a post request an complaining and throwing a 403 Forbidden "Could not verify the provided CSRF token because your session was not found." Which is expected because I when sending the post request the X-CSRF-TOKEN header is not being set but this header does exist:- Set-Cookie:XSRF-TOKEN=; Path=/

Angular:

auth.service.ts:

const body = 'SOMERANDOMKEY1111';

const headers = new HttpHeaders().set('Content-Type', 'application/json').set('withCredentials', 'true');

    return this._http.post(this.endpoint + this.auth, body, {
      headers: headers
    });

app.module.ts (note: using HttpClient for post request):

providers: [ ...
{
    provide: XSRFStrategy, useFactory: xsrfFactory
}...]
export function xsrfFactory() {
  return new CookieXSRFStrategy('XSRF-TOKEN', 'XSRF-TOKEN');
}

I've followed this and read up on the docs but can't seem to get this working.

Maj
  • 327
  • 4
  • 20

3 Answers3

2

i had same issue when i was started working with Spring and angular5 :

Q: how to set up X-CSRF token on each request made from angular ?

Sol : server side:

  • first you need to configure csrf security on server side

  • on server side you need to write one api which set up cookies on browser (X-CSRF token inside cookies) and this api is hitting without any securities(disable csrf on this api, assume api name /info)

NOTE : /info this api is called only once when angular app first time loaded (you need to add this is in first page which is to be loaded in angular app)

angular side :

  • when application is loaded on first page/component of angular , inside oninit you need to call this route "/info" (you need to create service in angular and call this api there) i set this on my layout/navbar component because when app is loaded this component was first one which loaded

  • then on inside app.module.ts we need to import

import { HttpClientModule } from '@angular/common/http';

and addd this module inside imports array as :

@NgModule({   imports: [
                     HttpClientXsrfModule.withOptions({
                     cookieName: 'XSRF-TOKEN',
                     headerName: 'X-XSRF-TOKEN',
         })]

-then inside services you need to change the request as follows: user.service.ts

 registeruser(data) {
    console.log(data)
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers, withCredentials: true });
    return this.http.post(this.url + '/avssymbuaa/api/register', data, options).map(res => res.json());
  }
  • note : you need to import this on service

import { Http, Headers, RequestOptions, Response, URLSearchParams } from '@angular/http';

may be this one helps you, thanks

Bhagvat Lande
  • 1,392
  • 3
  • 17
  • 34
0

The response is forbidden because the spring server or your proxy is expect to receive a X-CSRF token in the header and you did not send it.

1.Please make sure that you are doing a POST (on LOG IN) method to receive the CSRF-TOKEN

2.Store the token received in cookies or localstorage

3.Make the post and add token into the header like this:

let headers = new Headers({ 'XSRF-TOKEN', 'the token received after login' });
let options = new RequestOptions({ headers: headers });
return this.http.post(url,body,options);
RazvanParautiu
  • 2,805
  • 2
  • 18
  • 21
0

If your Angular UI and RESTful service are in different domains, your Angular code can't read the cookie set by your backend. To resolve that in your local workspace you can set up cli proxy But for production, if you are using Apache HTTP server, you need to set up reverse proxy. Here is an example:

For https

<VirtualHost *:443>
    ServerName localhost
    SSLEngine on
    SSLProxyEngine On
    SSLCertificateFile conf/ssl/newfile.crt
    SSLCertificateKeyFile conf/ssl/newfile.key
    ProxyPass /api/ https://yoursite/api/
    ProxyPassReverse /api/ https://yoursite/api/
</VirtualHost>

For http

<VirtualHost *:80>
    ServerName localhost
    ProxyPass /api/ http://yoursite/api/
    ProxyPassReverse /api/ http://yoursite/api/
</VirtualHost>
Community
  • 1
  • 1