I have followed roughly Scott's blog in combination with Joseph's blog. Unfortunately, I get the error Auth ErrorTypeError: Failed to fetch.
The config for authorization is like this ({tenantId}
is a valid GUID).
services.AddSwaggerGen(options =>
{
options.AddSecurityRequirement(new() { ... });
options.AddSecurityDefinition("oauth2", new()
{
Type = SecuritySchemeType.OAuth2,
Flows = new()
{
AuthorizationCode = new()
{
AuthorizationUrl = new("https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize"),
TokenUrl = new("https://login.microsoftonline.com/{tenantId}/common/v2.0/token"),
Scopes = new Dictionary<string, string>
{
{ "https://graph.microsoft.com/.default", "https://graph.microsoft.com/.default" }
}
}
}
});
});
Then, I also have the config for the UI like so ({clientId} is a valid GUID).
app.UseSwaggerUI(options =>
{
options.OAuthAppName("Beep");
options.OAuthClientId("{clientId}");
options.OAuthClientSecret("HakunaMatata");
options.OAuthScopes(["https://graph.microsoft.com/.default" ]);
options.OAuthUsePkce();
});
The authorization button in Swagger opens the popup and when requesting the call, the error above is returned. I don't understand where the problem occurs nor how I can troubleshoot it further. The only thing I noticed was that not providing any scopes, leads to an error message in Azure. Providing a scope won't even show the sign-in page there. I've verified that the .well-known produces correct values for authorization and token endpoints. I verified that the secret is correct for the app registration as well as the Redirect URI pointing to my Swagger (https://localhost:7001/swagger/oauth2-redirect.html). Most of the related questions deal with implicit flow or API key, which isn't applicable in my case. Similar questions regarding the error message are rather not rewarding. I also tried to declare a dedicated scope (api://d53180a4-0a79-4f7a-96aa-3f2eed32f559/SwaggerScope) and using it shows me the login page but picking a user produced the same error message.
I inspected the network calls and noticed something unexpected. Apparently, CORS is triggered on the token endpoint and it also reports 404 Not Found (which is self-contradictory but I imagine the not-find-ness is somehow caused by the CORS-ness). The URL is not what I specify in my config above (according to the .well-known endpoint) and I don't control the server to activate the allowed origins.
I created this project using Swagger UI Authorization for ASP.NET Core API, and it was successfully authorized without any errors.
Below is the code I used for Swagger UI Authentication.
builder.Services.AddSwaggerGen(
o =>
{
o.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "Swagger Azure Ad", Version = "v1" });
o.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Name = "oauth2.0",
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(builder.Configuration["SwaggerAAD:AuthorizationUrl"]),
TokenUrl = new Uri(builder.Configuration["SwaggerAAD:TokenUrl"]),
Scopes = new Dictionary<string, string>
{
{builder.Configuration["SwaggerAAD:Scope"],"Access API as User" }
}
}
}
});
o.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference=new OpenApiReference{Type=ReferenceType.SecurityScheme,Id="oauth2"}
},
new []{builder.Configuration["SwaggerAAD:Scope"]}
}
});
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(
o =>
{
o.OAuthClientId(builder.Configuration["SwaggerAAD:ClientId"]);
o.OAuthUsePkce();
o.OAuthScopeSeparator(" ");
});
}
Below is my complete Program.cs class.
Program.cs:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Web;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(
o =>
{
o.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "Swagger Azure Ad", Version = "v1" });
o.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Name = "oauth2.0",
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(builder.Configuration["SwaggerAAD:AuthorizationUrl"]),
TokenUrl = new Uri(builder.Configuration["SwaggerAAD:TokenUrl"]),
Scopes = new Dictionary<string, string>
{
{builder.Configuration["SwaggerAAD:Scope"],"Access API as User" }
}
}
}
});
o.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference=new OpenApiReference{Type=ReferenceType.SecurityScheme,Id="oauth2"}
},
new []{builder.Configuration["SwaggerAAD:Scope"]}
}
});
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(
o =>
{
o.OAuthClientId(builder.Configuration["SwaggerAAD:ClientId"]);
o.OAuthUsePkce();
o.OAuthScopeSeparator(" ");
});
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
I placed values such as ClientId, TenantId, AuthorizationUrl, and TokenUrl in appsettings.json instead of placing them in program.cs.
appSettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<YourDomain>.onmicrosoft.com",
"TenantId": "<YourTenantID>",
"ClientId": "<ClientId>",
"CallbackPath": "/signin-oidc",
"Scopes": "access_as_user"
},
"SwaggerAAD": {
"AuthorizationUrl": "https://login.microsoftonline.com/<TenantId>/oauth2/v2.0/authorize",
"TokenUrl": "https://login.microsoftonline.com/<TenantId>/oauth2/v2.0/token",
"Scope": "https://graph.microsoft.com/.default",
"ClientId": "<ClientId>"
},
For the Azure AD API App Registration, the redirect URL is placed in the web application as shown below.
For the SwaggerAAD App Registration, I placed the RedirectUrl in the Single-page application as shown below.
I took the endpoint values from the Swagger client app registration.
I have added the following API permissions below.
When I placed authorizationUrl and tokenUrl in Program.cs, I received the error below. So, I put these values in the appsettings.json file.
After putting the authorizationUrl and tokenUrl in the appsettings.json file, I received the output below without any errors.
Output: