scalar icon indicating copy to clipboard operation
scalar copied to clipboard

Can't authenticate with OAuth2 - "window was closed without granting authorization"

Open subzero10 opened this issue 8 months ago β€’ 6 comments

What happens?

Hello, I'm using Scalar.AspNetCore to setup the following authentication scheme:

settings.AddSecurity("bearer", new OpenApiSecurityScheme
            {
                Type = OpenApiSecuritySchemeType.OAuth2,
                Scheme = "Bearer",
                BearerFormat = "JWT",
                Flows = new OpenApiOAuthFlows
                {
                    AuthorizationCode = new OpenApiOAuthFlow
                    {
                        AuthorizationUrl = "https://auth.mydomain.com/connect/authorize",
                        Scopes = new Dictionary<string, string>
                        {
                            { "openid", "OpenId" },
                            { "profile", "Profile" },
                        }
                    }
                }
            });

When I go on the Scalar UI and click on Authorize, a new window opens and I'm immediately presented with an error on the parent window:

Window was closed without granting authorization

This happens before I even type my username and password in the new window. Please note that after I type my credentials, the new window is redirected to the Scalar UI with the authorization code in the URL (this is expected because this is what I have configured as my Redirect URI). This tells my that configuration is correct on my identity server.

I've tried to debug the code by attaching a debugger (with Chrome Dev Tools) and noticed the following error messages in authWindow.then here:

  • [Exception: SecurityError: Blocked a frame with origin "https://localhost:5004/" from accessing a cross-origin frame.] [Exception: SecurityError: An attempt was made to break through the security policy of the user agent.]

If my understanding is correct, this method of trying to read the location of the new window from the parent window is not allowed when the two windows are not under the same origin (scalar UI is running under "localhost:5004" and my authentication server is under "auth.mydomain.com"). Is this correct? Is there any way to work around this (perhaps not doing this in a different window)?

What did you expect to happen?

The app to read the authorization code from the new window and use it to get a token.

OpenAPI Document

No response

subzero10 avatar Mar 13 '25 14:03 subzero10

hmm that is strange, I think I built it using the oauth playground which works fine. Also the scalar galaxy example works as well with localhost + galaxy.scalar.com. Which browser and OS were you using? Could you put the spec in https://sandbox.scalar.com/ and see if it gives the same error?

amritk avatar Mar 20 '25 23:03 amritk

Same issue here, I put my spec in https://sandbox.scalar.com/ and I get the same error. Window was closed without granting authorization at standalone.js:24007:4

Chrome Version 134.0.6998.118 (Official Build) (64-bit) Windows 11 Pro 24H2

wesley-jochman avatar Mar 21 '25 18:03 wesley-jochman

FYI, we were able to resolve this by configuring our identity server to allow cross origin requests from our localhost:PORT domain.

Conclusion: I wouldn't say this is a bug, but I suggest to add a note somewhere in documentation that CORS should be configured on the identity server, since the authentication flow is happening from the client-side javascript code.

subzero10 avatar Mar 28 '25 16:03 subzero10

Ah, the auth provider I'm using doesn't support localhost except through a tunnel

wesley-jochman avatar Mar 28 '25 16:03 wesley-jochman

@amritk Feel free to close the issue, thanks!

subzero10 avatar Mar 28 '25 16:03 subzero10

Alright cool I will actually leave it open and see if we can detect that error then show a popup that mentions cors

amritk avatar Mar 28 '25 16:03 amritk

Hey I am getting a similar issue currently when I want to add oauth2 with azureAd/Entra.

When I open the scalar url and than click on the "authorize" button I get a notification in the bottom right saying "Window was closed without granting authorization", the actual small login window still opens and shows me the azur login screen. I than login into azure, but than it redirects me inside the new small window back to scalar but no JWT-Token is safed or put into the "auth bearer" Header value.

Before I was using SwaggerUI but there I suddenly get an error Uncaught TypeError: Cannot read properties of null (reading 'swaggerUIRedirectOauth2') at run (oauth2-redirect.html) after redirecting, so I thought it is a good time to switch to scalar.

What am I missing ?

My Code:

services.AddOpenApi("openapi", opt =>
        {
            opt.AddDocumentTransformer((document, _, _) =>
            {
                document.Info = new()
                {
					//...
                };

                return Task.CompletedTask;
            });

            opt.AddDocumentTransformer((document, _, _) =>
            {
                document.Components ??= new OpenApiComponents();

                document.Components.SecuritySchemes.Add("Bearer", new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.OAuth2,
                    Scheme = "Bearer",
                    BearerFormat = "JWT",
                    Flows = new OpenApiOAuthFlows
                    {
                        AuthorizationCode = new OpenApiOAuthFlow
                        {
                            AuthorizationUrl = new($"{appSettings.Instance}{appSettings.TenantId}/oauth2/v2.0/authorize"),
                            TokenUrl = new($"{appSettings.Instance}{appSettings.TenantId}/oauth2/v2.0/token"),
                            Scopes = { { appSettings.Scopes, "Web Api access" } },
                            // To allow Scalar to select PKCE by Default
                            // valid options are 'SHA-256' | 'plain' | 'no'
                            Extensions = new Dictionary<string, IOpenApiExtension>
                            {
                                ["x-usePkce"] = new OpenApiString("SHA-256"),
                            }
                        },
                    }
                });

                // Provide a security requirement for all operations (preselected default security scheme)
                document.SecurityRequirements.Add(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" },
                            Scheme = "Bearer",
                            Name = "Bearer",
                            In = ParameterLocation.Header
                        },
                        // scopes
                        []
                    }
                });

                return Task.CompletedTask;
            });
app.MapOpenApi("{documentName}.json");
        app.MapScalarApiReference("", options =>
        {
            options.WithTitle("Web Api")
                .WithOpenApiRoutePattern("/{documentName}.json")
                .WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient)
                .WithPreferredScheme("Bearer")

                .AddAuthorizationCodeFlow("Bearer",opt =>
                {
                    opt.AuthorizationUrl = new($"{appSettings.Instance}{appSettings.TenantId}/oauth2/v2.0/authorize");
                    opt.TokenUrl = new($"{appSettings.Instance}{appSettings.TenantId}/oauth2/v2.0/token");
                    opt.ClientId = appSettings.ClientId;
                    opt.Pkce = Pkce.Sha256;
                    opt.SelectedScopes = [appSettings.Scopes, "Web Api access"];
                });
        });

maxstue avatar May 08 '25 09:05 maxstue

I get a notification in the bottom right saying "Window was closed without granting authorization", the actual small login window still opens and shows me the azur login screen.

This was exactly my experience as well. I know very little about AzureAd/Entra, but see if you can configure your identity server to access cross origin request. A quick google search shows a number of results.

subzero10 avatar May 08 '25 10:05 subzero10

I get a notification in the bottom right saying "Window was closed without granting authorization", the actual small login window still opens and shows me the azur login screen.

This was exactly my experience as well. I know very little about AzureAd/Entra, but see if you can configure your identity server to access cross origin request. A quick google search shows a number of results.

Thanks for the fast reply, but sadly there isn't (or I can't find it) a setting in AzureAD/Entra for setting any CORS stuff. I only can find those settings on the action service/containers.

maxstue avatar May 13 '25 20:05 maxstue

We added some error handling when the server provides it now. Unfortunately we cannot do anything about CORS so I'm closing the ticket.

amritk avatar May 16 '25 05:05 amritk

Unfortunately we cannot do anything about CORS so I'm closing the ticket.

That's true about CORS, but I'm wondering if a different flow would work, instead of opening a new window and initiating the auth flow with JavaScript:

  • What if you redirect to the Identity server url (not in a new window)
  • User submits credentials
  • Identity Server redirects back to the Scalar url with some query params (the typical auth flow)
  • As the scalar app initializes, it applies the logic you have in oauth2.ts

Wouldn't this work?

subzero10 avatar May 16 '25 06:05 subzero10

It could but we would like to avoid changing the page as we use this same auth in other places as well. Ideally we could make something work with the popup.

amritk avatar May 16 '25 06:05 amritk