scalar
scalar copied to clipboard
Can't authenticate with OAuth2 - "window was closed without granting authorization"
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
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?
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
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.
Ah, the auth provider I'm using doesn't support localhost except through a tunnel
@amritk Feel free to close the issue, thanks!
Alright cool I will actually leave it open and see if we can detect that error then show a popup that mentions cors
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"];
});
});
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.
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.
We added some error handling when the server provides it now. Unfortunately we cannot do anything about CORS so I'm closing the ticket.
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?
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.