Documentation Index
Fetch the complete documentation index at: https://mintlify.com/zitadel/zitadel/llms.txt
Use this file to discover all available pages before exploring further.
.NET SDK
Integrate ZITADEL into .NET applications using the built-in ASP.NET Core OpenID Connect middleware. This approach leverages Microsoft’s well-tested authentication libraries for secure, production-ready integration.
Installation
The required packages are included in ASP.NET Core. For .NET 6+:
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect
Configuration
Configure OIDC authentication in your Program.cs:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
var builder = WebApplication.CreateBuilder(args);
// Add authentication services
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
// ZITADEL instance configuration
options.Authority = "https://your-instance.zitadel.cloud";
options.ClientId = builder.Configuration["Zitadel:ClientId"];
options.ClientSecret = builder.Configuration["Zitadel:ClientSecret"];
// PKCE flow
options.ResponseType = OpenIdConnectResponseType.Code;
options.UsePkce = true;
// Requested scopes
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("offline_access"); // For refresh tokens
// Claims mapping
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
// Callback paths
options.CallbackPath = "/auth/callback";
options.SignedOutCallbackPath = "/auth/logout/callback";
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Application Settings
Store configuration in appsettings.json:
{
"Zitadel": {
"Domain": "https://your-instance.zitadel.cloud",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret"
}
}
For production, use environment variables or Azure Key Vault:
dotnet user-secrets set "Zitadel:ClientId" "your-client-id"
dotnet user-secrets set "Zitadel:ClientSecret" "your-client-secret"
Authentication Flows
Login
Create a login endpoint:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Mvc;
public class AccountController : Controller
{
[HttpGet("login")]
public IActionResult Login(string returnUrl = "/")
{
var properties = new AuthenticationProperties
{
RedirectUri = returnUrl
};
return Challenge(properties, OpenIdConnectDefaults.AuthenticationScheme);
}
}
Logout
Implement federated logout:
[HttpGet("logout")]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var properties = new AuthenticationProperties
{
RedirectUri = Url.Action("Index", "Home")
};
return SignOut(properties, OpenIdConnectDefaults.AuthenticationScheme);
}
Protected Routes
Use the [Authorize] attribute:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[Authorize]
public class ProfileController : Controller
{
public IActionResult Index()
{
return View();
}
}
In Controllers
[Authorize]
public class ProfileController : Controller
{
public IActionResult Index()
{
var userId = User.FindFirst("sub")?.Value;
var email = User.FindFirst("email")?.Value;
var name = User.FindFirst("name")?.Value;
ViewBag.UserId = userId;
ViewBag.Email = email;
ViewBag.Name = name;
return View();
}
}
In Razor Views
@if (User.Identity?.IsAuthenticated == true)
{
<p>Welcome, @User.Identity.Name!</p>
<p>Email: @User.FindFirst("email")?.Value</p>
}
else
{
<a asp-controller="Account" asp-action="Login">Login</a>
}
Role-Based Authorization
Map ZITADEL roles to .NET claims:
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "urn:zitadel:iam:org:project:roles"
};
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = context =>
{
var roles = context.Principal?.FindFirst("urn:zitadel:iam:org:project:roles")?.Value;
// Process roles as needed
return Task.CompletedTask;
}
};
Authorize by Role
[Authorize(Roles = "admin")]
public class AdminController : Controller
{
public IActionResult Index()
{
return View();
}
}
API Authentication
JWT Bearer Token Validation
For API endpoints, validate JWT tokens:
using Microsoft.AspNetCore.Authentication.JwtBearer;
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://your-instance.zitadel.cloud";
options.Audience = "your-api-client-id";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true
};
});
Protect API Endpoints
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class UsersController : ControllerBase
{
[HttpGet]
public IActionResult GetUsers()
{
var userId = User.FindFirst("sub")?.Value;
// Return user data
return Ok();
}
[HttpGet("{id}")]
[Authorize(Roles = "admin")]
public IActionResult GetUser(string id)
{
// Admin-only endpoint
return Ok();
}
}
Calling ZITADEL APIs
Use the Management API from .NET:
using System.Net.Http.Headers;
using System.Text.Json;
public class ZitadelApiService
{
private readonly HttpClient _httpClient;
private readonly string _accessToken;
public ZitadelApiService(HttpClient httpClient, string accessToken)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new Uri("https://your-instance.zitadel.cloud");
_accessToken = accessToken;
}
public async Task<UserInfo> GetUserAsync(string userId)
{
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", _accessToken);
var response = await _httpClient.GetAsync($"/v2/users/{userId}");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<UserInfo>(content);
}
}
Best Practices
- Use PKCE: Always enable PKCE for web applications
- Secure Secrets: Never commit client secrets to source control
- HTTPS Only: Require HTTPS in production
- Token Storage: Use secure cookie settings for token storage
- Session Timeout: Configure appropriate session lifetimes
Resources
Next Steps