Reputation: 57
I'm trying to use AzureAD to get a token in swagger and test my controllers with it.
Here I'm logging with swagger-ui:
And just after this without use my personnal AzureAD Id, I'm already logged.
But when I try to use my controllers, I have the Error: Unauthorized
My controllers all inherit from a baseController. All of them have the [Authorize] annotation.
I don't really know where is the problem. I'm using Swashbuckle.AspNetCore v2.5.0
Some config code.
Statup.cs
public virtual void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Audience = "{client_id}";
options.Authority = "https://login.microsoftonline.com/{tenant_id}";
});
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v2", new Info
{
Title = "API",
Version = "v2",
Description = "Api Help",
Contact = new Contact()
{
Name = "John Doe",
Email = "[email protected]"
}
});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
options.AddSecurityDefinition("OAuth2", new OAuth2Scheme()
{
Flow = "implicit",
Type = "oauth2",
TokenUrl = "https://login.microsoftonline.com/{tenant_id}/oauth2/token",
Description = "OAuth2 Implicit Grant",
AuthorizationUrl = "https://login.microsoftonline.com/{tenant_id}/oauth2/authorize",
Scopes = new Dictionary<string, string>()
{
{ "user_impersonation", "Access api" }
}
});
options.OperationFilter<FileOperation>();
options.DescribeAllEnumsAsStrings();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<ExceptionHandlerMiddleware>();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("../swagger/v2/swagger.json", "API V2");
c.RoutePrefix = "Help";
c.OAuthClientId("{client_id_swagger_app}"); //Swagger
//c.OAuthClientId("client_id_api_app"); //api
c.DisplayRequestDuration();
c.OAuthClientSecret("{secret_client_key_swagger}"); //swagger secret
c.OAuthAppName("Swagger");
c.OAuthRealm("http://localhost:1234/swagger/ui/o2c-html");
c.OAuthScopeSeparator(" ");
c.OAuthUseBasicAuthenticationWithAccessCodeGrant();
c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>
{
{ "resource", "{app_ID_URI}"} //api
});
});
app.UseAuthentication();
app.UseMvc();
}
Upvotes: 3
Views: 2326
Reputation: 58733
You have configured Swagger UI to get an access token with the resource:
c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>
{
{ "resource", "{app_ID_URI}"} //api
});
But you have configured your valid audience as:
options.Audience = "{client_id}";
Swagger UI using the App ID URI is fine, and you can instead configure your API to accept both the client id and URI as audiences (Azure AD allows using both, so why not configure your API as such too?):
options.TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new List<string>{ "client-id", "app-id-uri"}
};
The above should go in your AddJwtBearer
configuration callback, and you can remove the options.Audience =
line.
To specify scopes required per action, you need to add an operation filter inside services.AddSwaggerGen(options =>{})
:
options.OperationFilter<AuthenticationOperationFilter>();
And define the filter that requires the OAuth scope on every action:
public class AuthenticationOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
operation.Security = new List<IDictionary<string, IEnumerable<string>>>
{
new Dictionary<string, IEnumerable<string>>
{
//Note "OAuth2" casing here must match the definition you use in Swagger UI config
["OAuth2"] = new List<string>{ "user_impersonation" }
}
};
}
}
What you have defined in the Swagger UI configuration defines what scopes the user can select when using the UI. Bear in mind that since you are using Azure AD v1 endpoints, what scopes you select will not matter. The token will always contain the scopes which have been consented, nothing more, nothing less.
Upvotes: 1