0

I have an Angular 8 app calling a .Net Core 3 backend API using:

this.http.get<User[]>('/users');

I am deliberately not passing a bearer token. The API expects an authorization bearer header and when the call above doesn't provide it, .Net correctly outputs in the log:

HTTP GET /users responded 401. AuthenticationScheme: Bearer was not authenticated

However the Angular debug console displays the following three entries for this, two of which are extraneous or plain wrong:

1) Failed to load resource: the server responded with a status of 401 () [https://localhost:5000/users]

2) Failed to load resource: the server responded with a status of 401 () [https://localhost:5000/users]

3) Access to XMLHttpRequest at 'https://localhost:5000/users' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. [http://localhost:4200/users]

My first problem is that item (2) above should not exist because there is no second http call or error returned.

My second problem is that item (3) above should not exist because I already have CORS setup however regardless .Net will not return a 'Access-Control-Allow-Origin' header if it is returning a 401.So why is Angular looking for one?

My third and most important problem is that in my httpinterceptor where I catch this error:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(request).pipe(catchError((error: HttpErrorResponse) => {

the error object caught is:

error.status = 0 This should be 401, but its 0

error.message = "Unknown Error" This should be "Unauthorized" or some such

So it seems to me that the httpinterceptor is actually being passed error number (3) from the above list as opposed to error number (1) like it should be.

Has anyone seen this before or know how to get round it?

5
  • All cross domain requests have an OPTIONS request and then the actual request. In this case you do not have CORS configured in .NET so you get the final error. Commented Oct 27, 2019 at 15:24
  • developer.mozilla.org/en-US/docs/Web/HTTP/CORS Commented Oct 27, 2019 at 15:26
  • Well as per the spec you linked to, GET does not include a preflight. And indeed I can see on my API server trace that there is no preflight being received (as verification if I separately call a POST endpoint then I see the preflight). I also already have CORS setup in my .Net API which I verify by correctly passing the JWT bearer token and everything works fine. So its really just the scenario where I dont include the bearer token that this weird situation happens. Didn't think there was any need to a downvote, to be honest... Commented Oct 27, 2019 at 15:38
  • 1
    Note the additional requirements in the documentation for GET requests not to require a preflight request: The only allowed values for the Content-Type header are: application/x-www-form-urlencoded; multipart/form-data; text/plain. And a status value of 0 is usually for CORS issues Commented Oct 27, 2019 at 17:17
  • I agree, it was a well asked question. I wasn't the downvote Commented Oct 28, 2019 at 14:13

1 Answer 1

3

This is due to a bug (or inconsistency in .Net Core 3): https://github.com/aspnet/AspNetCore/issues/16584

Basically, a .Net Core API will return CORS headers most of the time, unless the JWT bearer middleware rejects the bearer token for some reason (expired, missing, etc). In that case, no CORS headers are returned by .Net. The bug is that it should always return CORS headers to allow the calling client to properly process the response, even if it is a 401 "expired token" error.

The result is that the Angular http interceptor does not receive the 401 error from the API because Angular replaces it with the CORS "missing headers" error instead. This makes it difficult, and perhaps impossible, to properly respond to these responses in Angular, because you can't detect the original 401 status at all.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.