![]() |
VOOZH | about |
dotnet add package Dosaic.Plugins.Authorization.Zitadel --version 1.2.34
NuGet\Install-Package Dosaic.Plugins.Authorization.Zitadel -Version 1.2.34
<PackageReference Include="Dosaic.Plugins.Authorization.Zitadel" Version="1.2.34" />
<PackageVersion Include="Dosaic.Plugins.Authorization.Zitadel" Version="1.2.34" />Directory.Packages.props
<PackageReference Include="Dosaic.Plugins.Authorization.Zitadel" />Project file
paket add Dosaic.Plugins.Authorization.Zitadel --version 1.2.34
#r "nuget: Dosaic.Plugins.Authorization.Zitadel, 1.2.34"
#:package Dosaic.Plugins.Authorization.Zitadel@1.2.34
#addin nuget:?package=Dosaic.Plugins.Authorization.Zitadel&version=1.2.34Install as a Cake Addin
#tool nuget:?package=Dosaic.Plugins.Authorization.Zitadel&version=1.2.34Install as a Cake Tool
Dosaic.Plugins.Authorization.Zitadel is a plugin that provides OAuth2 token-introspection authentication against a Zitadel server. It registers the official Zitadel authentication scheme, validates Bearer tokens via the Zitadel introspection endpoint (using a JWT application profile), and exposes a management service for programmatically creating and managing service accounts and user accounts.
Application JWT profile; no manual key fetching requiredIManagementService — injectable service to list service accounts, create service accounts (with JWT keys), create human user accounts, and obtain Bearer tokens for service accountsILoggerdotnet add package Dosaic.Plugins.Authorization.Zitadel
Or add the package reference directly to your .csproj:
<PackageReference Include="Dosaic.Plugins.Authorization.Zitadel" Version="" />
The plugin is configured under the Zitadel key via the [Configuration("Zitadel")] attribute on ZitadelConfiguration.
[Configuration("Zitadel")]
public class ZitadelConfiguration
{
// Zitadel project ID (used to build the audience scope for service account tokens)
public required string ProjectId { get; set; }
// Zitadel organization ID (used when creating users/service accounts)
public required string OrganizationId { get; set; }
// Base URL of the Zitadel instance, e.g. "https://my-org.zitadel.cloud"
public required string Host { get; set; }
// When true (default), the authority URL uses https://; set to false for local/dev environments
public bool UseHttps { get; set; } = true;
// Whether to validate the issuer during OIDC discovery (default: true)
public bool ValidateIssuer { get; set; } = true;
// Whether to validate discovery endpoints (default: true)
public bool ValidateEndpoints { get; set; } = true;
// Enable caching of introspection results (default: true)
public bool EnableCaching { get; set; } = true;
// How long introspection results are cached (default: 1 minute)
public int CacheDurationInMinutes { get; set; } = 1;
// Prefix for cache keys (default: "ZITADEL_")
public string CacheKeyPrefix { get; set; } = "ZITADEL_";
// JSON string of the Zitadel Application JWT profile used for introspection
public required string JwtProfile { get; set; }
// JSON string of the Zitadel Service Account JWT profile used by IManagementService
public string ServiceAccount { get; set; }
}
Note: Passing an
http://host whileUseHttps = truewill throw anInvalidConfigurationExceptionat startup.
appsettings.yml exampleZitadel:
projectId: "23456789012345678"
organizationId: "123456789012345678"
host: https://my-org.zitadel.cloud
useHttps: true
validateIssuer: true
validateEndpoints: true
enableCaching: true
cacheDurationInMinutes: 1
cacheKeyPrefix: "ZITADEL_"
jwtProfile: |
{
"type": "application",
"keyId": "...",
"key": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----\n",
"appId": "...",
"clientId": "..."
}
serviceAccount: |
{
"type": "serviceaccount",
"keyId": "...",
"key": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----\n",
"userId": "..."
}
Zitadel:
host: http://localhost:8080
useHttps: false
validateIssuer: false
validateEndpoints: false
projectId: "1"
organizationId: "1"
jwtProfile: "{}"
serviceAccount: "{}"
When useHttps is false, the plugin uses http:// for the authority URL and relaxes discovery validation — useful when running Zitadel locally via Docker.
public class MyEndpoints : IPluginEndpointsConfiguration
{
public void ConfigureEndpoints(IEndpointRouteBuilder endpointRouteBuilder, IServiceProvider serviceProvider)
{
endpointRouteBuilder.MapGet("/hello", () => "Hello World!")
.RequireAuthorization();
endpointRouteBuilder.MapGet("/admin", () => "Admin area")
.RequireAuthorization(policy => policy.RequireRole("admin"));
}
}
[ApiController]
[Route("api/[controller]")]
public class ItemsController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult GetAll() => Ok();
[HttpGet("public")]
[AllowAnonymous]
public IActionResult Public() => Ok("no auth needed");
}
Authorization: Bearer <token> header is extracted from the incoming request.<host>/oauth/v2/introspect) together with the Application JWT profile loaded from JwtProfile.ClaimsPrincipal.EnableCaching = true, the introspection result is stored in the distributed cache under <CacheKeyPrefix><token-hash> for CacheDurationInMinutes to avoid repeated network calls.Error level by the plugin's ILogger<ZitadelPlugin>.IManagementService is registered automatically and can be injected to manage Zitadel users programmatically.
public interface IManagementService
{
// List all machine (service account) users in the configured organization
Task<List<ListServiceAccountResultItem>> ListServiceAccountsAsync();
// Create a new service account user and return its JWT key content
Task<ServiceAccountCreationResult> CreateServiceAccountAsync(
string userid, string name, Timestamp keyExpirationTime, string description = "");
// Obtain a Bearer token for a service account identified by its JSON key string
Task<string> GetBearerTokenForServiceAccountAsync(string jsonString);
// Create a human user account with an initial password
Task<string> CreateUserAccountAsync(
string userid, string email,
string displayName, string givenName, string familyName, string password);
}
public record ServiceAccountCreationResult(string UserId, string KeyId, string KeyContent);
public record ListServiceAccountResultItem(
string UserId, string State, string Name, string Description,
bool HasSecret, string Owner, DateTime CreatedAt, DateTime UpdatedAt);
public class MyService(IManagementService management)
{
public async Task PrintServiceAccounts()
{
var accounts = await management.ListServiceAccountsAsync();
foreach (var account in accounts)
Console.WriteLine($"{account.UserId} — {account.Name} ({account.State})");
}
}
var expirationTime = Timestamp.FromDateTime(DateTime.UtcNow.AddYears(1));
var result = await management.CreateServiceAccountAsync(
userid: "my-service-id",
name: "my-service",
keyExpirationTime: expirationTime,
description: "Service account for my-service");
Console.WriteLine($"UserId: {result.UserId}");
Console.WriteLine($"Key JSON: {result.KeyContent}");
Use GetBearerTokenForServiceAccountAsync (or call the Zitadel SDK directly) to obtain a Bearer token for a service account and attach it to outgoing HTTP requests.
// Using IManagementService (reads service account JSON from configuration)
var token = await managementService.GetBearerTokenForServiceAccountAsync(jwtProfileJsonString);
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "http://<api-url>/api/endpoint");
request.Headers.Add("Authorization", "Bearer " + token);
var response = await client.SendAsync(request);
Or call the Zitadel SDK directly when you need additional scopes:
var authOptions = new ServiceAccount.AuthOptions();
// be sure to include this scope or your introspection will not be able to verify token for the indented project
authOptions.AdditionalScopes.Add("urn:zitadel:iam:org:project:id:123456789012345678:aud");
authOptions.AdditionalScopes.Add("offline_access");
authOptions.AdditionalScopes.Add("profile");
authOptions.AdditionalScopes.Add("email");
var token = await ServiceAccount.LoadFromJsonString("<jwtProfileJsonString>")
.AuthenticateAsync("<HostUrl>", authOptions);
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "http://<api-url>/api/endpoint");
request.Headers.Add("Authorization", "Bearer " + token);
var response = await client.SendAsync(request);
The urn:zitadel:iam:org:project:id:<projectId>:aud scope tells Zitadel to include your project's audience in the token so the receiving API's introspection call succeeds.
| 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 | 93 | 6/10/2026 |
| 1.2.33 | 101 | 6/2/2026 |
| 1.2.31 | 102 | 5/28/2026 |
| 1.2.30 | 110 | 5/7/2026 |
| 1.2.29 | 107 | 5/5/2026 |
| 1.2.28 | 112 | 4/30/2026 |
| 1.2.27 | 99 | 4/29/2026 |
| 1.2.26 | 94 | 4/29/2026 |
| 1.2.25 | 117 | 4/27/2026 |
| 1.2.24 | 107 | 4/21/2026 |
| 1.2.23 | 114 | 4/14/2026 |
| 1.2.22 | 107 | 4/10/2026 |
| 1.2.21 | 112 | 4/10/2026 |
| 1.2.20 | 106 | 4/10/2026 |
| 1.2.19 | 107 | 4/9/2026 |
| 1.2.18 | 113 | 4/2/2026 |
| 1.2.17 | 104 | 4/1/2026 |
| 1.2.16 | 101 | 4/1/2026 |
| 1.2.15 | 104 | 3/31/2026 |
| 1.2.14 | 116 | 3/30/2026 |