1

I am implementing a simple authentication API that is configured with Spring Boot to be accessed via Basic Auth. This is a simple GET API without any parameters used only to force the browser to trigger the authentication window:

localhost:8080/api/auth

I consume this API from my Angular 7.3.10 project, which serves at

localhost:4200

At the same time I am using anti-CSRF protection, so I handle all API calls to have an additional header for the X-XSRF-TOKEN. This is my HttpInterceptor:

export class CustomHttpInterceptor implements HttpInterceptor {
    constructor(private xsrfTokenExtractor: HttpXsrfTokenExtractor) {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.url.startsWith(environment.apiUrl)) {
            // send request with credential options in order to be able to read cross-origin cookies
            req = req.clone({ withCredentials: true });

            // return XSRF-TOKEN in each request's header (anti-CSRF security)
            const headerName = 'X-XSRF-TOKEN';
            let token = this.xsrfTokenExtractor.getToken() as string;
            if (token !== null && !req.headers.has(headerName)) {
                req = req.clone({ headers: req.headers.set(headerName, token) });
            }
        }
        return next.handle(req);
    }
}

Now when I call the auth endpoint within my Angular app, I get to write my credentials and then I get the following error:

Access to XMLHttpRequest at 'http://localhost:8080/api/auth' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

There is a preflight request when interecepting my requests to add the XSRF token and this request does not hold the Basic Auth header, even though I give my credentials properly:

preflight request part 1 preflight request part 2

Now if I remove the part that adds the XSRF token from the interceptor, then the auth request works fine after I give my credentials. Of course it does not need the XSRF token, because it is a GET request, but in the future I need to use both Basic Auth and anti-CSRF protection with POST API calls, so it is necessary to be able to make both work. Any ideas?

Stefanos Kargas
  • 10,547
  • 22
  • 76
  • 101
  • 1
    I think the CORS configurations are not enabled on your server. The issue is not directly related to Anti-CSRF, but it is because the OPTIONS request has no server-side handling – Rasha Elsayed Jun 09 '21 at 18:57
  • it is not the CORS. I am handling it with Spring Boot. If I disable the basic auth, I get all requests (GET and POST) to work fine with preflight OPTIONS requests for each one of them. If you think about it shouldn't my OPTIONS request have basic auth creds in its headers? I believe this is the problem here. If you want I can share code of server-side config. – Stefanos Kargas Jun 10 '21 at 06:39
  • 1
    This is probably due to CORS configuration on your server side. It looks like your API is expecting credentials for the `OPTIONS` request. However, these requests are triggered by the browser and you cannot modify them to add custom headers, like you can see in your screenshot... so your server returns 401. Modify your CORS config server side so that no authentication is needed for `OPTIONS` requests – David Jun 10 '21 at 08:00
  • David, your answer worked. You can post it as an answer to get the bounty. – Stefanos Kargas Jun 10 '21 at 21:36

1 Answers1

2

As per my comment:

This is due to CORS configuration on the server side. It looks like the API is expecting credentials for the OPTIONS request. However, these requests are triggered by the browser and you cannot modify them to add custom headers, like you can see in your screenshot... so your server returns 401.

The solution is to modify the CORS config server side so that no authentication is needed for OPTIONS requests

David
  • 33,444
  • 11
  • 80
  • 118