2

I'm developing a C# web app (edit: Blazor WASM) where users are logged in via Azure AD.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(...)

It works well – the browsers send an HTTP authorization header with a bearer token that the middleware in my app interprets. I am now setting up a three-legged OAuth connection to a third-party server where my client app will make changes on the user's behalf. I am again using Microsoft middleware (Microsoft.AspNetCore.Authentication.OAuth):

services.AddAuthentication(...)
        .AddCookie()
        .AddOAuth(...);

It starts out well, and the browser is redirected to the third-party server's OAuth authorization URL. However, the CORS flow kicks in and the browsers send a preflight OPTIONS request to the server with headers like this:

OPTIONS /oauth2/auth?client_id=123abc[...]
Accept: */*
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Origin: https://localhost:7260

It seems like the browsers (I've tried both Firefox and Chrome) want to send "my" authorization header along to the third-party server. Unfortunately, the third-party server isn't able to respond properly to these requests. It just responds with a redirect to /home without any of the required headers, so the browsers throw errors and the flow stops.

I can't control the third-party server so I would like to avoid the preflight request. It doesn't trigger when I'm testing without being logged in to my client app, but in production I need the users to be logged in.

Is there some way I can prevent the browsers from trying to send the authorization header to the redirected page? I have played around with OnRedirectToAuthorizationEndpoint, but I didn't get anywhere.

Alternatively, can I set it up so that "my" user sessions are handled via a cookie instead of using the authorization header?

And finally, is there some good documentation of all this anywhere? I can always read the dotnet sources, but doing so is not very efficient.

Rolf Staflin
  • 2,092
  • 2
  • 22
  • 19
  • CORS should only kick in when doing HTTP requests via JS in the browser client. I don't understand how this could happen during a redirect to the 3rd party auth provider. – Good Night Nerd Pride Aug 01 '23 at 13:58
  • Is it possible that because you're using Blazor some code that should run in the backend is actually executed by the web frontend? – Good Night Nerd Pride Aug 01 '23 at 14:00
  • Thank you for responding! This should definitely be done by the browser. The point of the three-legged OAuth flow is that the end user should approve that my client app is allowed to access the resources on the third-party server, so it's important that they can verify that their browser is indeed showing a page from the server. If they aren't logged in already they will be asked to login first, and then they will be asked to grant or deny access. The browser will then be redirected back to a landing page on my client web app, along with a secret that my app can use to access the data. – Rolf Staflin Aug 02 '23 at 17:28
  • "is redirected to the third-party server's OAuth authorization URL." I second @GoodNightNerdPride . If this is happening on your client side you can not avoid the preflight request unless it is a get request. Get requests normally don't cause a preflight flow unless you are adding none-safe headers. [Some info about headers](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) – Eldar Aug 15 '23 at 05:56
  • Does this answer your question? [Access to fetch at https://accounts.google.com/o/oauth2/v2/auth has been blocked by CORS](https://stackoverflow.com/questions/72382892/access-to-fetch-at-https-accounts-google-com-o-oauth2-v2-auth-has-been-blocked) – Heiko Theißen Aug 18 '23 at 14:21
  • Unfortunately not, Heiko. In the app, the user clicks a regular HTML anchor tag, so the request to my server side is a regular GET which is then redirected to the OAuth server just as the standard dictates. This is all in a browsing context and works perfectly, except when the user is already logged into Azure AD (i. e., when that Authorization header is present). – Rolf Staflin Aug 18 '23 at 14:45
  • Then I second Good Night Nerd Pride: I don't understand why CORS would kick in in your case. Just to be sure: The `OPTIONS /oauth2/auth?client_id=123abc[...]` request that you mention is made by the browser to the Azure AD server, right? – Heiko Theißen Aug 19 '23 at 07:29
  • Not quite, Heiko. The user is already logged into Azure AD, which is why there is an Authorization HTTP header in the requests. The problem appears when I want the user to log in to another server via OAuth – I have called it the "third-party" server above. The options request is sent from the browser to _the third-party server_. It's frustrating because the only reason that the OPTIONS request is sent at all is because of that Authorization header from AAD, but the contents of the header is only valid on my server, not on the third-party server. – Rolf Staflin Aug 28 '23 at 11:59

1 Answers1

0

i am not much experience so correct me if i am wrong

services.AddCors(options =>
{
    options.AddPolicy("AllowAll", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader()
               .WithExposedHeaders("authorization"); // this line will allow //the authorization header
    });
});

then you apply the CORS policy to your app's middleware.

  • This is for a setup for the server. It configures the headers that the cors response will contain. The server doesn't send any auth headers in the response, unless you write a middleware for a good reason that copies the header from the request to the response. – Eldar Aug 15 '23 at 05:46
  • AFAIK `AllowAnyOrigin` does not work with authorization, at least according to docs. – Guru Stron Aug 15 '23 at 13:53
  • yes you are right. my mistake – Rainy sidewalks Aug 15 '23 at 17:59