Using Swagger with an ASP.NET WebAPI Secured by Auth0

Andrew Varnon
3 min readAug 10, 2020

I have 2 ASP.NET WebAPIs that are secured by Auth0. One is .NET 4.8 and the other is .NET Core 3.1. I want to be able to test both using Swagger.

To start, I created an application in Auth0: for Swagger. I configured this as Regular Web Applications. For the Swagger application, I enabled Client Credentials flow and set the Token Endpoint Authentication Method to Post.

Next, I create an API in Auth0. This is needed so that a user or machine authenticated in the Swagger application can talk to an API secured by the WebAPI application. Under the APIs Machine to Machine Applications, I needed to authorize the Swagger Application.

Lastly, I needed to configure the WebAPIs authentication and Swagger config to work with Auth0.

.NET 4.8

App_Start/Startup.Auth.cs

public void ConfigureAuth(IAppBuilder app)
{
var domain = $”https://{ConfigurationManager.AppSettings["Auth0:Domain"]}/";
var audience = ConfigurationManager.AppSettings[“Auth0:Audience”];
var keyResolver = new OpenIdConnectSigningKeyResolver(domain); // https://github.com/auth0/auth0-aspnet-owin/blob/master/src/Auth0.Owin.OpenIdConnectSigningKeyResolver/OpenIdConnectSigningKeyResolver.cs
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = audience,
ValidIssuer = domain,
IssuerSigningKeyResolver = (token, securityToken, kid, parameters) => keyResolver.GetSigningKey(kid),
},
});
}

App_Start/SwaggerConfig.cs

public static void Register()
{
string routePrefix = ConfigurationManager.AppSettings["Swagger:RoutePrefix"];
if (string.IsNullOrWhiteSpace(routePrefix)) routePrefix = "swagger";GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "My API");
c.OAuth2("oauth2.implicit")
.Description("OAuth2 Implicit Grant")
.Flow("implicit")
.AuthorizationUrl($"https://{ConfigurationManager.AppSettings["Auth0:Domain"]}/authorize");

c.OAuth2("oauth2.application")
.Description("OAuth2 Client Credentials Grant")
.Flow("application")
.TokenUrl($"https://{ConfigurationManager.AppSettings["Auth0:Domain"]}/oauth/token?audience={System.Web.HttpUtility.UrlEncode(ConfigurationManager.AppSettings["Auth0:Audience"])}");
c.OperationFilter<AssignOAuth2SecurityRequirements>();
})
.EnableSwaggerUi(c =>
{
c.EnableOAuth2Support(
clientId: ConfigurationManager.AppSettings["Swagger:ClientId"],
clientSecret: null,
realm: ConfigurationManager.AppSettings["Auth0:Domain"],
appName: "Swagger UI",
additionalQueryStringParams: new Dictionary<string, string>()
{
{ "audience", ConfigurationManager.AppSettings["Auth0:Audience"] },
}
);
Assembly resourceAssembly = typeof(SwaggerConfig).Assembly;
string resourceName = resourceAssembly.GetManifestResourceNames().SingleOrDefault(_ => _.IndexOf("auth0.js", StringComparison.InvariantCultureIgnoreCase) > -1);
c.InjectJavaScript(resourceAssembly, resourceName);
});
}

Auth0.js

This is to add support for Client Credentials flow. It should be an embedded resource.

var openUrl = null;(function (open) {
XMLHttpRequest.prototype.open = function (method, url) {
openUrl = url;
open.call(this, method, url);
};
})(XMLHttpRequest.prototype.open);
(function (send) {
XMLHttpRequest.prototype.send = function (body) {
if (body && body.indexOf('client_credentials') !== -1) {
// Copy from Query string to body
const urlParams = new URLSearchParams(openUrl.split('?')[1]);
const audience = urlParams.get('audience');
body += '&audience=' + audience;
}
send.call(this, body);
openUrl = null;
};
})(XMLHttpRequest.prototype.send);

.NET Core 3.1

wwwroot/js/Auth0.js

This is to add support for Client Credentials flow. It should be content.

var f = window.fetch;
window.fetch = function (url, opts) {
if (opts && opts.body && opts.body.indexOf('client_credentials') !== -1) {
// Copy from Query string to body
const urlParams = new URLSearchParams(opts.url.split('?')[1]);
const audience = urlParams.get('audience');
opts.body += '&audience=' + audience;
}
return f(url, opts);
};

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = $"https://{Configuration["Auth0:Domain"]}/";
options.Audience = Configuration["Auth0:Audience"];
});
services.AddControllers();c.SwaggerDoc("API", new OpenApiInfo()
{
Version = "v2",
Title = "My API",
});
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"https://{Configuration["Auth0:Domain"]}/authorize?audience={System.Web.HttpUtility.UrlEncode(Configuration["Auth0:Audience"])}", UriKind.Absolute),
},
ClientCredentials = new OpenApiOAuthFlow()
{
TokenUrl = new Uri($"https://{Configuration["Auth0:Domain"]}/oauth/token?audience={System.Web.HttpUtility.UrlEncode(Configuration["Auth0:Audience"])}", UriKind.Absolute),
},
},
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme()
{
Reference = new OpenApiReference()
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2",
},
},
Enumerable.Empty<string>().ToList()
},
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();app.UseStaticFiles();app.UseRouting();app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.OAuthClientId(Configuration["Swagger:ClientId"]);
c.InjectJavascript("/js/Auth0.js");
});
}

Settings

  • Auth0:Domain: the domain of the Auth0 Tenant
  • Auth0:Audience: the audience of the Auth0 API
  • Swagger:ClientID the Client ID of the Swagger Auth0 Application

--

--

Andrew Varnon

I am a full stack developer and architect, specializing in .Net and Azure.