KeyCloak.ManagementApi 1.4.2

dotnet add package KeyCloak.ManagementApi --version 1.4.2
                    
NuGet\Install-Package KeyCloak.ManagementApi -Version 1.4.2
                    
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="KeyCloak.ManagementApi" Version="1.4.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="KeyCloak.ManagementApi" Version="1.4.2" />
                    
Directory.Packages.props
<PackageReference Include="KeyCloak.ManagementApi" />
                    
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 KeyCloak.ManagementApi --version 1.4.2
                    
#r "nuget: KeyCloak.ManagementApi, 1.4.2"
                    
#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 KeyCloak.ManagementApi@1.4.2
                    
#: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=KeyCloak.ManagementApi&version=1.4.2
                    
Install as a Cake Addin
#tool nuget:?package=KeyCloak.ManagementApi&version=1.4.2
                    
Install as a Cake Tool

KeyCloak.ManagementApi

A .NET Standard 2.0 library for interacting with KeyCloak's Management API, designed with a similar API structure to Auth0.ManagementApi for easier migration from Auth0 to KeyCloak.

Compatibility

  • .NET Standard 2.0 (compatible with .NET Framework 4.6.1+ and .NET Core 2.0+)
  • .NET Framework 4.6.1+
  • .NET Core 2.0+
  • .NET 5.0+
  • .NET 6.0+
  • .NET 8.0+

Installation

You can reference this project directly or package it as a NuGet package.

To create a NuGet package:

dotnet pack -c Release

Getting Started

Authentication

First, you need to obtain an access token from KeyCloak. This can be done using client credentials flow:

using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;

public async Task<string> GetAccessTokenAsync(
    string keycloakUrl,
    string realm,
    string clientId,
    string clientSecret)
{
    using (var httpClient = new HttpClient())
    {
        var tokenEndpoint = $"{keycloakUrl}/realms/{realm}/protocol/openid-connect/token";

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("grant_type", "client_credentials"),
            new KeyValuePair<string, string>("client_id", clientId),
            new KeyValuePair<string, string>("client_secret", clientSecret)
        });

        var response = await httpClient.PostAsync(tokenEndpoint, content);
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        dynamic result = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
        return result.access_token;
    }
}

Initialize the Management API Client

using KeyCloak.ManagementApi;

var keycloakUrl = "https://keycloak.example.com";
var realm = "master";
var accessToken = await GetAccessTokenAsync(keycloakUrl, realm, clientId, clientSecret);

var client = new ManagementApiClient(keycloakUrl, realm, accessToken);

Usage Examples

User Management

Get all users
var users = await client.Users.GetAllAsync();
foreach (var user in users)
{
    Console.WriteLine($"{user.Username} - {user.Email}");
}
Get a specific user
var user = await client.Users.GetAsync("user-id-here");
Console.WriteLine($"User: {user.Username} ({user.Email})");
Create a new user
using KeyCloak.ManagementApi.Models;

var newUser = new UserCreateRequest
{
    Username = "john.doe",
    Email = "john.doe@example.com",
    FirstName = "John",
    LastName = "Doe",
    Enabled = true,
    EmailVerified = true,
    Credentials = new List<Credential>
    {
        new Credential
        {
            Type = "password",
            Value = "SecurePassword123!",
            Temporary = false
        }
    }
};

var userId = await client.Users.CreateAsync(newUser);
Console.WriteLine($"Created user with ID: {userId}");
Update a user
var updateRequest = new UserUpdateRequest
{
    Email = "newemail@example.com",
    FirstName = "John",
    LastName = "Doe",
    Enabled = true
};

await client.Users.UpdateAsync("user-id-here", updateRequest);
Delete a user
await client.Users.DeleteAsync("user-id-here");
Reset user password
await client.Users.ResetPasswordAsync("user-id-here", "NewPassword123!", temporary: false);

Role Management

Get all roles
var roles = await client.Roles.GetAllAsync();
foreach (var role in roles)
{
    Console.WriteLine($"Role: {role.Name} - {role.Description}");
}
Create a new role
var newRole = new RoleCreateRequest
{
    Name = "premium-user",
    Description = "Premium user role with additional privileges"
};

await client.Roles.CreateAsync(newRole);
Assign roles to a user
// Get the roles you want to assign
var roles = await client.Roles.GetAllAsync();
var premiumRole = roles.Find(r => r.Name == "premium-user");

await client.Users.AssignRolesAsync("user-id-here", new List<Role> { premiumRole });
Get user's roles
var userRoles = await client.Users.GetRolesAsync("user-id-here");
foreach (var role in userRoles)
{
    Console.WriteLine($"User has role: {role.Name}");
}

Client (Application) Management

Get all clients
var clients = await client.Clients.GetAllAsync();
foreach (var c in clients)
{
    Console.WriteLine($"Client: {c.ClientId} - {c.Name}");
}
Create a new client
var newClient = new ClientCreateRequest
{
    ClientId = "my-app",
    Name = "My Application",
    Enabled = true,
    PublicClient = false,
    StandardFlowEnabled = true,
    DirectAccessGrantsEnabled = true,
    ServiceAccountsEnabled = true,
    RedirectUris = new List<string>
    {
        "https://myapp.example.com/callback"
    },
    WebOrigins = new List<string>
    {
        "https://myapp.example.com"
    }
};

var clientId = await client.Clients.CreateAsync(newClient);
Console.WriteLine($"Created client with ID: {clientId}");
Get client secret
var secret = await client.Clients.GetSecretAsync("client-id-here");
Console.WriteLine($"Client secret: {secret}");
Regenerate client secret
var newSecret = await client.Clients.RegenerateSecretAsync("client-id-here");
Console.WriteLine($"New client secret: {newSecret}");

Group Management

Get all groups
var groups = await client.Groups.GetAllAsync();
foreach (var group in groups)
{
    Console.WriteLine($"Group: {group.Name} ({group.Path})");
}
Create a new group
var newGroup = new GroupCreateRequest
{
    Name = "administrators"
};

var groupId = await client.Groups.CreateAsync(newGroup);
Add user to a group
await client.Users.JoinGroupAsync("user-id-here", "group-id-here");
Get group members
var members = await client.Groups.GetMembersAsync("group-id-here");
foreach (var member in members)
{
    Console.WriteLine($"Member: {member.Username}");
}
Create a subgroup
var subGroup = new GroupCreateRequest
{
    Name = "sub-admins"
};

var subGroupId = await client.Groups.CreateSubGroupAsync("parent-group-id", subGroup);

Migration from Auth0.ManagementApi

The API structure is intentionally similar to Auth0.ManagementApi. Here's a comparison:

Auth0 Code:

// Auth0
var auth0Client = new ManagementApiClient(token, new Uri(domain));
var users = await auth0Client.Users.GetAllAsync(new GetUsersRequest());
var user = await auth0Client.Users.GetAsync("user-id");

KeyCloak Equivalent:

// KeyCloak
var keycloakClient = new ManagementApiClient(baseUrl, realm, token);
var users = await keycloakClient.Users.GetAllAsync();
var user = await keycloakClient.Users.GetAsync("user-id");

Key Differences from Auth0

  1. Realm-based: KeyCloak is multi-tenant with realms, so you specify the realm when initializing
  2. Authentication: You need to obtain the access token separately (typically using client credentials flow)
  3. User Attributes: In KeyCloak, custom attributes are stored in a dictionary: Dictionary<string, List<string>>
  4. Client vs Application: What Auth0 calls "Applications" or "Clients", KeyCloak also calls "Clients"

Error Handling

The library throws exceptions on API errors. Always wrap calls in try-catch blocks:

try
{
    var user = await client.Users.GetAsync("user-id");
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"API Error: {ex.Message}");
}

Custom HttpClient

If you need to configure the HttpClient (for proxies, custom timeouts, etc.):

var httpClient = new HttpClient
{
    Timeout = TimeSpan.FromSeconds(30)
};

var client = new ManagementApiClient(keycloakUrl, realm, accessToken, httpClient);

License

This project is provided as-is for migrating from Auth0 to KeyCloak.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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.4.2 100 2/26/2026
1.3.0 86 2/25/2026
1.2.1 104 2/12/2026
1.2.0 93 2/3/2026
1.1.0 118 1/15/2026
1.0.0 121 1/14/2026

Version 1.4.2:
     - Fixed BulkGrantRolesToUserAsync and BulkRevokeRolesFromUserAsync endpoint paths (was missing /users/ segment)

     Version 1.4.1:
     - Fixed GetAllAsync to paginate through all organizations (Phase Two API defaults to small page size)
     - Added GetPageAsync for explicit pagination control

     Version 1.4.0:
     - Added SearchByAttributeAsync for searching organizations by attribute query (q parameter)

     Version 1.3.0:
     - Added Phase Two Organizations support (IOrganizationsClient)
     - Organization CRUD (GetAll, Get, Create, Update, Delete)
     - Organization members (Add, Remove, GetMembers, SetMemberAttributes)
     - Organization roles (GetRoles, CreateRole, DeleteRole)
     - Role-user assignment (AssignRoleToUser, RemoveRoleFromUser)
     - Composite org role extension (LinkClientRolesToOrgRole)
     - Added realm-level API methods to ApiConnection for Phase Two endpoints

     Version 1.2.1:
     - Fixed GetByEmailAsync to use exact match instead of partial/LIKE search
     - Fixed GetByClientIdAsync to properly URL-encode the clientId parameter

     Version 1.2.0:
     - Added FederatedIdentities support in User model
     - Added GetUsersRequest with advanced filtering (username, email, firstName, lastName, enabled, emailVerified, search)
     - Added attribute-based query filtering using the Query parameter
     - Added PaginationInfo for improved pagination support

     Version 1.1.0:
     - Added client role management for users (GetClientRolesAsync, AssignClientRolesAsync, RemoveClientRolesAsync)
     - Added client role management (GetRolesAsync, CreateRoleAsync, DeleteRoleAsync)

     Version 1.0.0:
     - Initial release
     - User management (CRUD operations, password reset, role assignments)
     - Role management (realm and client roles)
     - Client management (CRUD operations, secret management)
     - Group management (CRUD operations, subgroups, memberships)
     - Compatible with .NET Framework 4.6.1+ and .NET Core 2.0+