CSRF Token not updated properly (Ionic + Spring Security)

Viewed 476

I'm developing an app using Ionic Framework and generated a JHipster project for my backend. My JHipster project runs on an extra Server and is called via REST requests from my App. So my problem now is handling the CORS and CSRF configuration.

My JHipster project has its own frontend, which runs on the same domain and while testing I can reach my backend without any issues. However, when I want to call my backend on the server from my Ionic app my xsrf tokens wont update properly and, therefore, I cannot access my backend. I already tried several solutions from different stack overflow posts, but none of them worked for me.

For example:

What I've done so far:

  1. I enabled csrf in my SecurityConfiguration in my JHipster project
        http
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .and()
            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
            .exceptionHandling()
            .authenticationEntryPoint(problemSupport)
            .accessDeniedHandler(problemSupport)
  1. added CORS configuration
  cors:
    allowed-origins: 'http://localhost:8100, ionic://localhost, http://localhost'
    allowed-methods: 'POST, GET, OPTIONS, DELETE, PUT, HEAD'
    allowed-headers: 'Origin, X-Requested-With, Content-Type, Accept, x-auth-token, Authorization, X-CSRF-Token, x-xsrf-token, XSRF-TOKEN'
    exposed-headers: 'Authorization,Link,X-Total-Count,XSRF-TOKEN, X-XSRF-TOKEN'
    allow-credentials: true
    max-age: 86400
  1. wrote an interceptor
@Injectable()
export class HttpXSRFInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor, private csrfService:CSRFService,  private $sessionStorage: SessionStorageService) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const headerName = 'XSRF-TOKEN';
    const respHeaderName = 'X-XSRF-TOKEN';
    let token = this.tokenExtractor.getToken() as string;

    if (token !== null && !req.headers.has(headerName)) {
      req = req.clone({ headers: req.headers.set(respHeaderName, token) });
      req.clone({
        withCredentials: true
      });
    }
    return next.handle(req);
  }
}
  1. added HttpClientXsrfModule in my app.module.ts and the interceptor
    HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-XSRF-TOKEN',
    }),
    {
      provide: HTTP_INTERCEPTORS,
      useClass:  HttpXSRFInterceptor,
      multi: true
    },

My Problem:

I dont get a xsrf token when starting my App in the browser, but after I send a post request the token gets set as a cookie.

For example when logging in, the first attempt fails due to the missing token, but the second login request is successful because now the response header for the xsrf token is not null anymore. Furthermore, the token does not update itself even though the server response has a new token in its header.

From my understanding

  1. the first time I get my token should be immediately after loading the start page of my app

  2. the token should be updated after each response from the server (backend) and the updated token is used for the next request

Therefore my problem is that both these issues do not happen and I don't know how to fix it.

I appreciate any help!

cheers

1 Answers

I'm the author of Ionic for JHipster so hopefully, I can help you with this.

First of all, CSRF shouldn't be an issue unless you're running your apps on the same port. In my experience, when you run them on separate ports, your client can't read the cookie. As for CORS, that's not a problem for me when running locally. I believe it's because the CORS settings for the dev profile are wide open. Can you try using the settings from the dev profile in your prod profile and see if it helps?

For reference, they are:

jhipster:
  cors:
    allowed-origins: '*'
    allowed-methods: '*'
    allowed-headers: '*'
    exposed-headers: 'Authorization,Link,X-Total-Count'
    allow-credentials: true
    max-age: 1800

If this works, I'd try changing your allowed origins to an array, or just use one. http://localhost:8100 should be all you need if running locally.

Related