In modern applications, securing your API endpoints becomes crucial. Leveraging Keycloak, an open source identity and access management solution, you can efficiently secure a .NET 8 Web API. When integrated with Swagger—a tool for API documentation and testing—you can enable interactive API exploration while ensuring authorization using Keycloak.
This guide presents an in-depth walkthrough on how to integrate Keycloak with a .NET 8 Web API project, configure Swagger for proper OAuth2-based authentication, and effectively secure endpoints using JWT Bearer tokens. By following this comprehensive approach, you can facilitate both robust security practices and an interactive testing environment for your API consumers.
The first step is to have a functioning Keycloak server. You can run Keycloak using Docker for convenience. For instance, using Docker, you can start Keycloak with the following command:
# Run Keycloak in Docker
docker run -p 8080:8080 \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:26.1.1 start-dev
Once running, access the Keycloak Admin Console by navigating to http://localhost:8080/admin and log in with the credentials provided (e.g., admin/admin).
A realm in Keycloak acts as a namespace for related configurations. Create a new realm (for example, "MyRealm") and then define a client. The client represents your .NET 8 Web API application.
http://localhost:5000/swagger/oauth2-redirect.html
.Make sure to note the Client ID and Client Secret since these will be used later in your .NET configuration.
To integrate Keycloak authentication into your .NET 8 Web API project, you must install several NuGet packages. These packages include support for JWT Bearer tokens, OpenID Connect, and Swagger for interactive API documentation.
Run the following commands in your terminal:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect
dotnet add package Swashbuckle.AspNetCore
These packages set up the fundamental infrastructure to enable secure communication between your API, Swagger, and Keycloak.
It’s a good practice to configure your Keycloak parameters in an appsettings.json file. This centralizes configuration and eases maintenance. Here is an example configuration:
{
"Keycloak": {
"realm": "MyRealm",
"auth-server-url": "http://localhost:8080/",
"ssl-required": "none",
"resource": "my-web-api",
"credentials": {
"secret": "your-client-secret"
}
}
}
Replace "MyRealm", "my-web-api", and "your-client-secret" with your actual realm name, client ID, and client secret from Keycloak.
The heart of the integration lies in your Program.cs file where authentication services are registered, JWT Bearer options are specified, and Swagger is configured to support OAuth2 flows. Below is a detailed example configuration:
// Necessary namespaces
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
// Load Keycloak configuration from appsettings.json
var keycloakConfig = builder.Configuration.GetSection("Keycloak");
// Configure JWT Bearer Authentication using Keycloak settings
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
// Authority is Keycloak's url plus realm
options.Authority = $"{keycloakConfig["auth-server-url"]}realms/{keycloakConfig["realm"]}";
options.Audience = keycloakConfig["resource"];
options.RequireHttpsMetadata = false; // Change to true in production
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
});
// Add Authorization support
builder.Services.AddAuthorization();
// Registering Swagger services with OAuth2 support
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
// Define API information
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "My Web API",
Version = "v1"
});
// Define the OAuth2.0 scheme that's in use (implicit flow)
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri($"{keycloakConfig["auth-server-url"]}realms/{keycloakConfig["realm"]}/protocol/openid-connect/auth"),
TokenUrl = new Uri($"{keycloakConfig["auth-server-url"]}realms/{keycloakConfig["realm"]}/protocol/openid-connect/token"),
Scopes = new Dictionary<string, string>
{
{ "openid", "OpenID Connect scope" },
{ "profile", "Profile information" },
{ "email", "Email address" }
}
}
}
});
// Enforce security requirements globally
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
new[] { "openid", "profile", "email" }
}
});
});
var app = builder.Build();
// Configure middleware pipeline
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "My Web API V1");
// Configure Swagger UI to use OAuth2 authentication
options.OAuthClientId(keycloakConfig["resource"]);
options.OAuthClientSecret(keycloakConfig["credentials:secret"]);
options.OAuthUsePkce(); // Recommended for enhanced security
});
}
// Enable HTTPS redirection and authentication middleware
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
// Sample API endpoint that is secured
app.MapGet("/protected", () => "Hello, authenticated user!")
.RequireAuthorization();
app.MapControllers();
app.Run();
The above configuration uses JWT Bearer authentication that pulls its authority URL from Keycloak. The Swagger UI is also set up using OAuth2 Security Definitions to interact seamlessly with Keycloak, which ensures that developers and testers can authenticate via the Swagger interface.
Once the authentication mechanism is in place, the next critical step is securing your API endpoints using the [Authorize]
attribute. This attribute restricts access to endpoints only to authenticated users.
For example, consider the following controller implementation:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
// This action is secured, requiring authentication and authorization
[HttpGet]
[Authorize]
public IActionResult GetForecast()
{
return Ok(new
{
Message = "This is a protected weather forecast endpoint."
});
}
}
This simple example illustrates how you protect your endpoints. You can also implement role-based authorization or policy-based checks if your application demands finer control over access.
In more demanding scenarios, you may wish to restrict endpoints based on user roles. Keycloak includes roles in the JWT, which you can extract via the realm_access
claim. In .NET, you can create authorization policies that examine these roles:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
policy.RequireClaim("realm_access", "admin"));
});
// Usage within a controller action
[Authorize(Policy = "AdminOnly")]
public IActionResult GetAdminData()
{
return Ok("Welcome admin!");
}
An essential aspect of this integration is ensuring that the Swagger UI facilitates interactive authentication. Once properly configured, users can click the “Authorize” button within Swagger to initiate the OAuth2 flow via Keycloak.
In the Swagger setup code in Program.cs, you set the OAuthClientId
and related fields. This configuration instructs Swagger to direct authentication requests to Keycloak. The steps are:
This means that on clicking “Authorize” in the Swagger UI, you are redirected to Keycloak to log in. Once authentication is successful, Swagger receives a token and makes authenticated requests on behalf of the user.
Below is a table summarizing important Keycloak configuration settings and their roles in a .NET project:
Configuration Parameter | Description | Example Value |
---|---|---|
realm | Namespace for Keycloak configurations | MyRealm |
auth-server-url | Base URL for the Keycloak server | http://localhost:8080/ |
resource | Client ID used for the application | my-web-api |
credentials.secret | Client secret for confidential access | your-client-secret |
Valid Redirect URIs | Allowed callbacks for OAuth2 authentication | http://localhost:5000/swagger/oauth2-redirect.html |
This table serves as a quick reference guide when configuring both Keycloak and your .NET 8 Web API.
After setting up Keycloak and successfully configuring your .NET 8 Web API with Swagger, the final step is testing the integration. The process involves:
dotnet run
).[Authorize]
attribute) are not accessible unless a valid token is provided.Once everything is working as expected, your application is now secured, and Swagger enables you to test authenticated calls seamlessly.
In conclusion, integrating Keycloak into a .NET 8 Web API provides a robust security framework utilizing industry-standard OAuth2 flows. This guide has walked through the installation and configuration of Keycloak, its integration with .NET through essential NuGet packages, and the detailed setup of authentication in Program.cs. Additionally, Swagger UI has been configured for OAuth2, allowing interactive testing and API exploration with secure endpoints.
The key benefits of this approach are clear: a centralized identity management system, a secure mechanism to handle authentication via JWT Bearer tokens, and a streamlined developer experience. Furthermore, by utilizing a well-defined authorization strategy (such as role-based policies), you can enhance security by limiting access to sensitive endpoints. These techniques not only safeguard the API but also simplify the testing process, making it easier to validate both the security logic and the API functionality.
As you deploy and scale such an application, remember to enforce additional security best practices like HTTPS in production and continuously monitor authentication flows. Advanced logging and error handling can further bolster your application’s resilience.