7

I have an asp.net core application using swagger library

<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />

Id like to allow the api developers using the /swagger web page to be able to obtain a token using the "ClientCredentials" flow. I have tried the below but am getting an options preflight issue

        c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
        {
            Type = SecuritySchemeType.OAuth2,
            Flows = new OpenApiOAuthFlows
            {
                ClientCredentials = new OpenApiOAuthFlow
                {
                    TokenUrl = new Uri(baseAuthURL + "/oauth2/v2.0/token"),
                    Scopes = new Dictionary<string, string>
                    {
                        { "ABC/.default", "Access read operations" }
                    },
                    AuthorizationUrl = new Uri(baseAuthURL + "/oauth2/authorize")
                }
            }
        });

when I click authorize

enter image description here

Upon viewing the console, here is what I see

Access to fetch at 'https://login.microsoftonline.com/ABCD/oauth2/v2.0/token' from origin 'https://localhost:44312' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

How can I work around this issue? What changes exactly need to be made to "AddSecurityDefinition" to work around this issue? Is this something that I am even able to work around? (assuming identity provider can support the options preflight request)

Is the only single workaround to create a reverse proxy?

How can I extend the code above to send custom HTTP request headers in the request?

I have searched for hours online of an example of someone successfully using ClientCredentials flow to obtain an oauth token within swaggerUI.

Update 1: What is very strange is that even though the options preflight request is receiving a response with the header access-control-allow-origin : * if I use a chrome extension to override this value to the exact same value, it works around the issue. Its obviously not a solution, but more of an observation. It is very odd that setting the value equal to the exact same value somehow changes the outcome.

Below is a diff of the response headers. Left side without any chrome extension, right side with chrome extension overridding to exact same value. You can see there is no difference. So why might the browser be treating this differently? enter image description here

I have also tried adding an authorization api proxy using AWS API Gateway, which you can see the response headers set below. This does not work either. enter image description here

Judy007
  • 5,484
  • 4
  • 46
  • 68

2 Answers2

0

I got to read through the NET Core CORS documentation: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#preflight-requests-1

Browsers aren't consistent in how they set Access-Control-Request-Headers. If either:

  • Headers are set to anything other than "*"
  • AllowAnyHeader is called: Include at least Accept, Content-Type, and Origin, plus any custom headers that you want to support.

... and Swagger docs: https://swagger.io/docs/open-source-tools/swagger-ui/usage/cors/

In my similar case, I had to enable CORS in the API using this configuration (notice the headers):

        services.AddCors(options =>
        {
            options.AddPolicy(CorsPolicyName, configure =>
            {
                configure
                    .WithHeaders(
                       //Microsoft minimum set recommended 
                       "Accept", "Content-Type", "Origin", 
                       //Swagger headers
                       "api_key", "authorization", "x-requested-with" )
                    .WithOrigins(...);
            });
        });

You could also allow for any header, it is a compromise between a one-for-all solution and exposure/security

Alex Pollan
  • 863
  • 5
  • 13
-1

Add this to your services configuration in Starup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy("AnyOrigin", builder =>
        {
            builder =>                              
                builder.WithOrigins("https://login.microsoftonline.com")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
        });
    });
}

Then this to your application configuration:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env
{
    // after routing / mvc
    app.UseCors("AnyOrigin");
}

Note that you're sending a authorization header, hence a credentials request and that translates to an Access-Control-Allow-Credentials CORS header. The endpoint needs to return a 200 OK and this should work.

For more help on this related to SwaggerUI, the following is a useful resource: https://swagger.io/docs/open-source-tools/swagger-ui/usage/cors/

Rebecca
  • 13,914
  • 10
  • 95
  • 136