Search code examples
angularspring-bootcsrfx-xsrf-token

How to access XSRF cookie value in Angular?


I have been working at this for the last 7 hours and cannot seem to make any headway. I am trying to get my XSRF-TOKEN available to the frontend (Angular 6). However, it seems that it is never available. When I perform analysis in the network tab and look under "Cookie" it appears to be there in all its shining glory. However, if I use Angular's CookieService and attempt to retrieve it nothing comes back.

Things to keep in mind:

  1. When run on my local machine I am able to get the XSRF-TOKEN out and place it in future header requests.
  2. The issue occurs when the two frontend and backend (Spring-boot) are hosted on two different hosts but under the same domain. For example: Frontend could be frontend.home.com; Backend could be backend.home.com.
  3. HttpOnly is set to False.
  4. Angular's withCredentials property is set to true as well.

I would really appreciate any suggestions on how to proceed with this seemingly trivial yet frustrating issue.

Thanks.

Backend:

http.httpBasic()
    .authenticationEntryPoint(new AuthenticationFailureHandler())
    .and()
        .authorizeRequests()
        .antMatchers("List of URL").permitAll()
        .anyRequest().authenticated()
    .and()
        .csrf()
        .ignoringAntMatchers("List of API to ignore CSRF Token")
        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
    .and()
        .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
http.logout()
    .permitAll()
    .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));
}

@Autowired
private CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    return repository;
}

Frontend:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let newHeaders: HttpHeaders = req.headers;

    let csrfToken = this.cookieService.get("XSRF-TOKEN");
    if (csrfToken === null || csrfToken === undefined) {
        newHeaders = newHeaders.append('X-XSRF-TOKEN', 'undefined');
    } else {
        newHeaders = newHeaders.append('X-XSRF-TOKEN', csrfToken);
    }

    const authReq = req.clone({headers: newHeaders, withCredentials: true});
    return next.handle(authReq);
}

Also, when I look at the developer tools I see three different domains.

  1. home.com
  2. backend.home.com (XSRF cookie is only found here and not accessible elsewhere)
  3. frontend.home.com

Solution

  • Based on the edits and the comments, you probably need to change the Cookie Domain of the CSRF cookie to be set on the home.com domain, instead of on the backend.home.com domain only. You can achieve that by changing the CookieCsrfTokenRepository:

    CookieCsrfTokenRepository repository = CookieCsrfTokenRepository.withHttpOnlyFalse();
    repository.setCookieDomain("home.com");
    
    http.httpBasic()
        .authenticationEntryPoint(new AuthenticationFailureHandler())
        .and()
            .authorizeRequests()
            .antMatchers("List of URL").permitAll()
            .anyRequest().authenticated()
        .and()
            .csrf()
            .ignoringAntMatchers("List of API to ignore CSRF Token")
            .csrfTokenRepository(repository)
        .and()
            .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
    http.logout()
        .permitAll()
        .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));
    }
    

    See the first two lines where the repository is setup like I wrote above and then used as the token repository.