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:
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?
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