In this blog post, we’ll walk through how to secure a .NET 8 Web API using Auth0 for authentication, specifically focusing on the Client Credentials flow. This setup is ideal for machine-to-machine communication, where one service needs to securely access another without user interaction.
When building modern web APIs, securing endpoints is a critical requirement. One of the most effective ways to secure your API is by using OAuth 2.0 with JWT tokens. Auth0 simplifies this process by providing a robust identity management solution that handles authentication and authorization for your applications.
In this guide, we’ll create a .NET 8 Web API, configure it to use Auth0 for securing endpoints, and demonstrate how to obtain and use JWT tokens via the Client Credentials flow.
Start by creating a new .NET 8 Web API project.
dotnet new webapi -n Auth0WebApi
cd Auth0WebApi
This command creates a new Web API project in a folder named Auth0WebApi
.
My API
https://myapi.com
RS256
My Machine-to-Machine App
).read:weather
).In your terminal, navigate to the project directory and add the required NuGet packages:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Swashbuckle.AspNetCore
appsettings.json
Open appsettings.json
and add the following configuration:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Auth0": {
"Domain": "your-tenant.auth0.com",
"ClientId": "YOUR_CLIENT_ID",
"ClientSecret": "YOUR_CLIENT_SECRET",
"Audience": "https://myapi.com"
}
}
Replace your-tenant.auth0.com
, YOUR_CLIENT_ID
, YOUR_CLIENT_SECRET
, and https://myapi.com
with your actual Auth0 domain, client ID, client secret, and API identifier.
Program.cs
Modify Program.cs
to include JWT Bearer authentication, authorization, and Swagger configuration:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
ClientCredentials = new OpenApiOAuthFlow
{
TokenUrl = new Uri($"https://{builder.Configuration["Auth0:Domain"]}/oauth/token"),
Scopes = new Dictionary<string, string>
{
{ "read:weather", "Read weather information" }
}
}
}
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
new List<string> { "read:weather" }
}
});
});
// Configure JWT Bearer authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = $"https://{builder.Configuration["Auth0:Domain"]}/";
options.Audience = builder.Configuration["Auth0:Audience"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidIssuer = $"https://{builder.Configuration["Auth0:Domain"]}/",
ValidateAudience = true,
ValidAudience = builder.Configuration["Auth0:Audience"],
ValidateLifetime = true,
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API v1");
c.OAuthClientId(builder.Configuration["Auth0:ClientId"]);
c.OAuthClientSecret(builder.Configuration["Auth0:ClientSecret"]);
c.OAuthAppName("My API - Swagger");
});
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization(); // Secures the endpoint
app.Run();
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
To test the API, you’ll need to obtain a JWT token from Auth0 using the Client Credentials flow. Use the following cURL
command:
curl --request POST \
--url https://your-tenant.auth0.com/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"https://myapi.com","grant_type":"client_credentials"}'
Replace the placeholders with your actual values.
dotnet run
https://localhost:5001
in your browser./weatherforecast
endpoint:By following this guide, you’ve successfully secured a .NET 8 Web API using Auth0 with the Client Credentials flow. This setup ensures that only authorized clients can access your API, making it a secure choice for machine-to-machine communication.
Auth0 provides a powerful and flexible solution for handling authentication and authorization, allowing you to focus on building features for your application while ensuring security.
Feel free to ask questions or share your experience with implementing this solution in the comments below!
This blog post provides a comprehensive guide to setting up and securing a .NET 8 Web API using Auth0. It should serve as a useful resource for developers looking to integrate OAuth 2.0 and JWT authentication into their applications.