Xzawed.Keycloak.Sdk 1.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package Xzawed.Keycloak.Sdk --version 1.0.1
                    
NuGet\Install-Package Xzawed.Keycloak.Sdk -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Xzawed.Keycloak.Sdk" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Xzawed.Keycloak.Sdk" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Xzawed.Keycloak.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Xzawed.Keycloak.Sdk --version 1.0.1
                    
#r "nuget: Xzawed.Keycloak.Sdk, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Xzawed.Keycloak.Sdk@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Xzawed.Keycloak.Sdk&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Xzawed.Keycloak.Sdk&version=1.0.1
                    
Install as a Cake Tool

Keycloak SDK for .NET

An async-first Keycloak client library for .NET that covers both Authentication (OIDC / OAuth2) and the Admin REST API behind one consistent facade.

Part of a nine-language polyglot SDK (Java · Python · Node · Go · C# · PHP · Rust · Ruby · Kotlin) whose concepts, layers, and flows are isomorphic across every language — github.com/xzawed/KeyCloakSDK.

1.0.1 is on NuGet — a patch release of security and correctness fixes on top of 1.0.0, the first release carrying the stability guarantee set out under Versioning and support below. A bare dotnet add package Xzawed.Keycloak.Sdk resolves it. It stops the PKCE verifier and tokens leaking through the default serializer (present in 1.0.0), caps JWKS and discovery response sizes, stops an empty 200 JWKS key set from replacing a good cached one, backs off failed JWKS fetches, and no longer returns a token response of the wrong shape as a success. ⚠️ A ServerUrl that is not an absolute http(s) URL is now rejected up front with a KeycloakConfigException, instead of escaping as a UriFormatException on the first call.

Requirements

  • .NET 8+ — the package targets net8.0.
  • A Keycloak server to connect to (integration-tested against Keycloak 26.6).

Every network method returns Task<T> and takes a trailing CancellationToken ct = default; only CreateAuthorizationRequest is synchronous, because it needs no network.

Install

dotnet add package Xzawed.Keycloak.Sdk

The root namespace is Xzawed.Keycloak (Admin resources live in Xzawed.Keycloak.Admin).

Quickstart

using Keycloak.AuthServices.Sdk.Admin.Models;
using Xzawed.Keycloak;

var config = new KeycloakConfig
{
    ServerUrl = "https://kc.example.com",
    Realm = "myrealm",
    ClientId = "admin-cli",
    ClientSecret = "changeme", // load from an env var / secret manager
};

// await using: DisposeAsync() releases the auth resources and, if used, the admin client.
await using var kc = KeycloakClient.Create(config);

// 1. Get a token (client-credentials grant). TokenSet.ToString() masks the tokens as "***".
var tokens = await kc.Auth.ClientCredentialsTokenAsync();
Console.WriteLine(tokens);

// 2. Validate it (hardened, see below).
var vt = await kc.Auth.ValidateAsync(tokens.AccessToken);
Console.WriteLine($"subject={vt.Subject} aud=[{string.Join(",", vt.Audience)}]");

// 3. Call the Admin API. The admin facade is built lazily on first AdminAsync().
var admin = await kc.AdminAsync();
var userId = await admin.Users.CreateAsync(new UserRepresentation { Username = "alice", Enabled = true });
Console.WriteLine($"created userId={userId}");

Audience — validation requires the token's aud to contain ClientId. A stock realm does not put the client id in a client-credentials token's aud, so on a default realm either set ExpectedAudience = "my-api" to the audience your realm issues, or add an Audience protocol mapper to the client in Keycloak.

Dependency injection is optional — KeycloakClient.Create(config) works standalone. If you do use a container, register the client as a singleton:

builder.Services.AddKeycloak(config); // registers KeycloakConfig + KeycloakClient as singletons

Admin failures surface as KeycloakNotFoundException / KeycloakConflictException / KeycloakForbiddenException (all carrying KeycloakAdminException.StatusCode), or KeycloakTransportException on a network failure.

Security defaults

  • Algorithm pinning — the accepted signature algorithms are fixed by config (RS256 by default); alg: none and unsigned tokens are rejected. Microsoft.IdentityModel leaves ValidAlgorithms unset, which accepts every algorithm it supports, so the SDK pins it explicitly.
  • Strict claim checks — exact iss match, aud containment check, mandatory exp, and a bounded clock skew (30s by default, down from the library's 5 minutes).
  • Rate-limited JWKS refetch — key sets are cached and refetches are throttled to a minimum interval (JwtValidatorOptions.RefreshIntervalSeconds, 30s by default — the same value as the other eight SDKs). Read this one precisely: unlike its sibling SDKs, this one cannot promise that a bad signature never causes a refetch. Microsoft.IdentityModel treats signature-validation failure as a possible key rotation and refreshes through its ConfigurationManager, and that behaviour cannot be disabled without giving up the manager entirely. The refresh interval is what bounds the amplification — measured, 6 forged tokens produce 1 extra fetch, not 6. A failed fetch is bounded separately: consecutive failures back off exponentially (0.2s, doubling, capped at 5s, with jitter), and inside that window the SDK fails fast without contacting the IdP. So a cold cache during an IdP outage no longer turns every validation into a request (measured: 20 attempts → 2 requests, down from 40 — this lane spends two requests per attempt, so one window costs two). ⚠️ The SDK never sleeps — it returns the error immediately, so retry pacing stays the caller's decision.
  • Secret handling — KeycloakConfig, TokenSet and AuthorizationRequest mask secrets, tokens and the PKCE CodeVerifier as *** in ToString() and JSON serialization, and TLS verification is on by default.

Masking covers ToString() and the types' JSON converters. It does not cover Serilog-style destructuring — {@Config} reads the properties directly and will print the raw secret, so log these three types with {Config}, not {@Config}.

Versioning and support

This SDK is 1.0 and follows SemVer: a breaking change to the public API requires a major bump. That promise is machine-backed — CI diffs this lane's public API against the previously published artifact on every build (the .NET SDK’s Package Validation, run during dotnet pack), and a removal or an incompatible change fails the build. ⚠️ The gate compares the API surface. A change that leaves the surface identical but alters behaviour is not caught by it, so read the release notes before upgrading.

Only the newest released version of each language SDK receives security fixes; there are no long-term-support lines and older releases are not backported to.

Each of the nine languages versions independently. All nine reached 1.0.0 in the same release wave because they earned the same guarantee at the same time — they do not move in lockstep afterwards.

Documentation

License

Apache-2.0 — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 155 9/26/2026
1.0.1 168 9/26/2026
1.0.0 1,066 8/31/2026
0.1.1 181 8/28/2026
0.1.0 110 8/17/2026
0.1.0-rc.1 94 8/2/2026