DhokoAuthaz
DocumentationAPI Reference
  • Get Started

    • Authaz
    • Core Concepts
    • Set up your app
    • Quickstart — cURL
  • Authentication

    • Authentication Settings
    • Signup
    • Invitations
    • Password Authentication
    • Multi-Factor Auth
    • Magic Link
    • OAuth / Social Login
    • Passkey (WebAuthn)
    • SAML SSO
    • Machine-to-Machine (M2M)
    • API Keys
  • Authorization

    • Authorization
    • Resources
    • Policies
    • Roles
    • Access Explorer
  • Tenancy

    • Multi-tenancy
    • Tenancy Customization
  • Brand & Host

    • Branding
    • Custom Domains
    • Communications & Email Templates
  • Operate

    • Users
    • Analytics
    • Audit Logs
    • Application Settings
  • SDK Quickstarts

    • Quickstart — Next.js
    • Quickstart — React SPA
    • Quickstart — Hono
    • Quickstart — .NET (Authaz.Sdk)
  • Recipes

    • Recipes & Cookbook
    • Next.js — first integration
    • Next.js — B2B SaaS (multi-tenant)
    • Hono — first integration
    • Hono — B2B SaaS (multi-tenant)
    • React SPA — first integration
    • React SPA — B2B SaaS (multi-tenant)
    • .NET — first integration
    • .NET — B2B SaaS (multi-tenant)
  • Reference

    • Tokens
    • API Reference
    • Errors & Troubleshooting
  • Documentation

    • How Authaz is Built
  1. Authaz
  2. Docs
  3. Recipes
  4. .NET — first integration

Recipes

.NET — first integration

2 min read·Updated May 7, 2026

← All recipes · First time? Set up your app (60 seconds — keys + redirect URI)

A minimal ASP.NET Core 10 web app that signs a user in via Authaz Sign-In and uses Authaz.Sdk to call the Management API. Single-tenant, password provider, no roles.

1. What you'll build#

An ASP.NET Core minimal API where / is public, /dashboard is protected by Authaz OIDC login, and a /me/profile endpoint reads the signed-in user from the Management API.

2. Application setup#

In the Authaz Dashboard:

  1. New application → name it, choose Single-tenant.
  2. Note the Client ID and Client Secret.
  3. Under Auth Flow Configuration, add https://localhost:5001/signin-oidc as an allowed callback URL.
Previous
React SPA — B2B SaaS (multi-tenant)
Next
.NET — B2B SaaS (multi-tenant)
  • API Keys → Create API Key → grant users:read. Copy the key (it shows once).
  • …or via the Management API:

    POST https://your-app.authaz.io/api/v1/applications
    X-API-Key: mgmt_01h...
     
    { "name": "my-aspnet-app", "tenancy_type": "single_tenant" }

    3. Install#

    dotnet add package Authaz.Sdk
    dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect

    4. Configure#

    appsettings.json:

    {
      "Authaz": {
        "Authority": "https://auth.authaz.io",
        "ClientId": "app_01h...",
        "ClientSecret": "secret_...",
        "ApiBaseUrl": "https://your-app.authaz.io",
        "ApiKey": "mgmt_01h..."
      }
    }

    In production, move ClientSecret and ApiKey to user secrets, environment variables, or a secrets manager — never commit them.

    5. Wire it up#

    Program.cs:

    using Authaz.Sdk;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.IdentityModel.Protocols.OpenIdConnect;
     
    var builder = WebApplication.CreateBuilder(args);
    var authaz = builder.Configuration.GetSection("Authaz");
     
    builder.Services
        .AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(options =>
        {
            options.Authority = authaz["Authority"];
            options.ClientId = authaz["ClientId"];
            options.ClientSecret = authaz["ClientSecret"];
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.UsePkce = true;
            options.SaveTokens = true;
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            options.GetClaimsFromUserInfoEndpoint = true;
        });
     
    builder.Services.AddAuthorization();
     
    // Authaz.Sdk wiring for Management API calls
    builder.Services.AddTransient<ApiKeyAuthHandler>();
    builder.Services
        .AddHttpClient("ManagementApi", c => c.BaseAddress = new Uri(authaz["ApiBaseUrl"]!))
        .AddHttpMessageHandler<ApiKeyAuthHandler>();
    builder.Services.AddScoped<ManagementApiClient>();
    builder.Services.AddScoped<UsersApiClient>();
    builder.Services.Configure<AuthazSdkOptions>(o => o.ApiKey = authaz["ApiKey"]!);
     
    var app = builder.Build();
    app.UseAuthentication();
    app.UseAuthorization();
     
    app.MapGet("/", () => "Welcome. <a href='/login'>Sign in</a>");
     
    app.MapGet("/login", () =>
        Results.Challenge(new() { RedirectUri = "/dashboard" },
            new[] { OpenIdConnectDefaults.AuthenticationScheme }));
     
    app.MapPost("/logout", async (HttpContext ctx) =>
    {
        await ctx.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        await ctx.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
        return Results.Redirect("/");
    });

    dotnet run → https://localhost:5001/login → Authaz Sign-In page → back to /dashboard.

    6. Read the user#

    After OIDC login, claims are on User. The sub claim is the Authaz user ID; email is their email.

    app.MapGet("/dashboard", (HttpContext ctx) =>
    {
        var sub = ctx.User.FindFirst("sub")?.Value;
        var email = ctx.User.FindFirst("email")?.Value;
        return Results.Ok(new { userId = sub, email });
    }).RequireAuthorization();

    7. Call the Management API#

    Inject the typed client and call. Authaz.Sdk throws ManagementApiException on non-2xx — let it bubble or map it:

    app.MapGet("/me/profile", async (HttpContext ctx, UsersApiClient users) =>
    {
        var sub = ctx.User.FindFirst("sub")?.Value;
        if (!Guid.TryParse(sub, out var userId)) return Results.Unauthorized();
     
        try
        {
            var user = await users.GetAsync(userId);
            return Results.Ok(new { user.Id, user.Email, user.IsActive, user.MfaEnabled });
        }
        catch (ManagementApiException ex) when (ex.StatusCode == 404)
        {
            return Results.NotFound();
        }
    }).RequireAuthorization();

    8. Common gotchas#

    • /signin-oidc is the ASP.NET OIDC callback path. ASP.NET's OIDC handler writes to it. Whatever URL you registered with Authaz must match this exactly (host, port, scheme).
    • Run on HTTPS in dev. OIDC cookies are Secure by default. Use dotnet dev-certs https --trust.
    • Persist Data Protection keys when scaling out. Without it, every instance issues incompatible cookies. See ASP.NET Data Protection docs.
    • The sub claim is a Guid string. Guid.TryParse it — never Guid.Parse (descriptive errors beat a generic FormatException).
    • Don't expose the Management API key to the browser. It's a server-side credential. The OIDC ClientSecret and the X-API-Key are different things — keep both server-side.

    9. Next steps#

    • Multi-tenant .NET recipe — same app shape with tenants and tenant-scoped permission checks
    • .NET SDK quickstart — every typed client surface in Authaz.Sdk
    • Security policies — password rules, MFA, session timeouts