![]() |
VOOZH | about |
dotnet add package Dosaic.Plugins.Authorization.Keycloak --version 1.2.34
NuGet\Install-Package Dosaic.Plugins.Authorization.Keycloak -Version 1.2.34
<PackageReference Include="Dosaic.Plugins.Authorization.Keycloak" Version="1.2.34" />
<PackageVersion Include="Dosaic.Plugins.Authorization.Keycloak" Version="1.2.34" />Directory.Packages.props
<PackageReference Include="Dosaic.Plugins.Authorization.Keycloak" />Project file
paket add Dosaic.Plugins.Authorization.Keycloak --version 1.2.34
#r "nuget: Dosaic.Plugins.Authorization.Keycloak, 1.2.34"
#:package Dosaic.Plugins.Authorization.Keycloak@1.2.34
#addin nuget:?package=Dosaic.Plugins.Authorization.Keycloak&version=1.2.34Install as a Cake Addin
#tool nuget:?package=Dosaic.Plugins.Authorization.Keycloak&version=1.2.34Install as a Cake Tool
Dosaic.Plugins.Authorization.Keycloak is a plugin that provides JWT-based authentication and role-driven authorization against a Keycloak server. It implements a custom ASP.NET Core authentication scheme that validates Bearer tokens using Keycloak's realm public key, maps realm and client roles to ClaimTypes.Role, and exposes named authorization policies that can be applied to minimal API endpoints or MVC controllers.
keycloak authentication scheme — validates JWT Bearer tokens without a full OIDC discovery round-trip; fetches the realm public key once and caches it in memoryrealm_access and resource_access JWT claims and adds them as ClaimTypes.Role claimsIAuthorizationService automaticallyEnabled: false to run without any authentication (an allow-all default policy is registered), useful for local development9000, path /health/ready) tagged as readinessauthentication_keycloak_success and authentication_keycloak_noresult counters plus a HandleAuthenticateAsync span per authentication attempt on the shared Dosaic ActivitySourcedotnet add package Dosaic.Plugins.Authorization.Keycloak
Or add the package reference directly to your .csproj:
<PackageReference Include="Dosaic.Plugins.Authorization.Keycloak" Version="" />
The plugin is configured under the keycloak key via the [Configuration("keycloak")] attribute on KeycloakPluginConfiguration.
[Configuration("keycloak")]
public class KeycloakPluginConfiguration
{
// Toggle the entire plugin. When false, an allow-all authorization policy is registered
// and no authentication middleware is added.
public bool Enabled { get; set; }
// Hostname of the Keycloak authentication server (required when Enabled = true)
public string Host { get; set; }
// Optional port for the authority URI (omit to use the default HTTPS/HTTP port)
public int? Port { get; set; }
// When true, uses http:// instead of https:// for the authority URI
public bool Insecure { get; set; }
// OAuth2 client ID (used to resolve resource_access roles)
public string ClientId { get; set; }
// OAuth2 client secret
public string ClientSecret { get; set; }
// Realm URL configuration
public RealmsConfig Realms { get; set; } = new RealmsConfig();
// Named authorization policies available in the application
public IList<AuthPolicy> Policies { get; set; } = new List<AuthPolicy>();
// Health check endpoint configuration (defaults to port 9000, path /health/ready)
public HealthCheckConfig HealthCheck { get; set; } = new HealthCheckConfig();
}
public class RealmsConfig
{
// URL path prefix used to build the realm public-key endpoint
public string Prefix { get; set; } = "/auth/realms";
// Default realm name
public string Default { get; set; } = "master";
}
public class HealthCheckConfig
{
// When true, uses http:// for the health check URL (default: true)
public bool Insecure { get; set; } = true;
// Hostname for the Keycloak management/health endpoint
public string Host { get; set; }
// Port for the management endpoint (default: 9000)
public int? Port { get; set; } = 9000;
// Path for the health check (default: /health/ready)
public string Prefix { get; set; } = "/health/ready";
}
appsettings.yml examplekeycloak:
enabled: true
host: keycloak.example.com # public Keycloak hostname
port: 443 # optional; omit to use default HTTPS port
insecure: false # false = https (recommended for production)
clientId: my-service
clientSecret: supersecret
realms:
prefix: /auth/realms
default: master
policies:
- name: READ
roles:
- API_PERMISSIONS_READ
- name: WRITE
roles:
- API_PERMISSIONS_WRITE
healthCheck:
host: keycloak-internal.example.com # internal management host
port: 9000
insecure: true # management port typically not TLS
prefix: /health/ready
keycloak:
enabled: false
When enabled is false, no authentication is required and all requests are allowed through. A warning is logged at startup.
public class MyEndpoints : IPluginEndpointsConfiguration
{
public void ConfigureEndpoints(IEndpointRouteBuilder endpointRouteBuilder, IServiceProvider serviceProvider)
{
// Require named policy per verb
endpointRouteBuilder
.AddSimpleRestResource<MyResource>(serviceProvider, "my-resource")
.ForGet(cfg => cfg.WithPolicies("READ"))
.ForGetList(cfg => cfg.WithPolicies("READ"))
.ForPost(cfg => cfg.WithPolicies("WRITE"))
.ForPut(cfg => cfg.WithPolicies("WRITE"))
.ForDelete(cfg => cfg.WithPolicies("WRITE"))
.ForAll(cfg => cfg.WithPolicies("WRITE", "READ")); // apply to all verbs at once
// Or use standard ASP.NET Core policy requirement directly
endpointRouteBuilder.MapGet("/hello", () => "Hello World!").RequireAuthorization("READ");
}
}
[ApiController]
[Route("api/[controller]")]
public class ItemsController : ControllerBase
{
[HttpGet]
[Authorize("READ")]
public IActionResult GetAll() => Ok();
[HttpPost]
[Authorize("WRITE")]
public IActionResult Create([FromBody] Item item) => Ok();
[HttpGet("public")]
[AllowAnonymous]
public IActionResult Public() => Ok("no auth needed");
}
Authorization: Bearer <token> header is extracted from the incoming request.iss (issuer) claim, which contains the Keycloak realm URL.PublicKeyService fetches the realm's public key from <authority><realms.prefix>/<realm> and caches it in memory for the lifetime of the process.JwtSecurityTokenHandler with ValidateIssuerSigningKey = true, ValidateLifetime = true, and ValidateAudience = false.realm_access.roles array and — when a client ID is present (azp claim) — also from resource_access.<clientId>.roles.ClaimTypes.Role claims, making them available to [Authorize(Roles = "...")] and RequireRole policies.Policies are registered from KeycloakPluginConfiguration.Policies and require the user to have all listed roles:
// Registered automatically — no manual code required:
// options.AddPolicy("READ", builder => builder.RequireRole("API_PERMISSIONS_READ"));
// options.AddPolicy("WRITE", builder => builder.RequireRole("API_PERMISSIONS_WRITE"));
The default policy requires an authenticated user (i.e., a valid Keycloak token). Unauthenticated requests to unprotected endpoints are still allowed.
The plugin registers a URL health check named keycloak tagged as readiness:
GET http(s)://<healthCheck.host>:<healthCheck.port><healthCheck.prefix>
With the defaults above this resolves to http://keycloak-internal.example.com:9000/health/ready. The health check returns Unhealthy if the endpoint does not respond with a success status code.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.34 | 97 | 6/10/2026 |
| 1.2.33 | 99 | 6/2/2026 |
| 1.2.31 | 96 | 5/28/2026 |
| 1.2.30 | 102 | 5/7/2026 |
| 1.2.29 | 97 | 5/5/2026 |
| 1.2.28 | 103 | 4/30/2026 |
| 1.2.27 | 102 | 4/29/2026 |
| 1.2.26 | 102 | 4/29/2026 |
| 1.2.25 | 106 | 4/27/2026 |
| 1.2.24 | 98 | 4/21/2026 |
| 1.2.23 | 113 | 4/14/2026 |
| 1.2.22 | 105 | 4/10/2026 |
| 1.2.21 | 109 | 4/10/2026 |
| 1.2.20 | 98 | 4/10/2026 |
| 1.2.19 | 109 | 4/9/2026 |
| 1.2.18 | 112 | 4/2/2026 |
| 1.2.17 | 105 | 4/1/2026 |
| 1.2.16 | 109 | 4/1/2026 |
| 1.2.15 | 114 | 3/31/2026 |
| 1.2.14 | 113 | 3/30/2026 |