C# / ASP.NET Core Quickstart
Wire LumoAuth into an ASP.NET Core 8 app with the official
LumoAuth.AspNetCore package. It registers the SDK
from appsettings.json, signs browsers in through OpenID Connect, resolves
LumoAuth bearer tokens on API requests, and enforces permissions server-side
with [RequirePermission].
Prerequisites
- .NET 8 SDK or newer
- An OAuth client registered with redirect URI
https://localhost:5001/signin-lumoauth(the portdotnet runprints).
Register the client in the portal under Applications → New application: enter an Application name, choose Web application, enter the Redirect URI, and click Create application. The client secret is shown once, on the page you land on.
Install
dotnet new web -o lumo-demo && cd lumo-demo
dotnet add package LumoAuth.AspNetCore
appsettings.json:
{
"LumoAuth": {
"BaseUrl": "https://app.lumoauth.dev",
"OrgId": "your-org-slug",
"ApiKey": "lmk_...",
"Login": {
"ClientId": "lumo_...",
"ClientSecret": "..."
}
}
}
Keep the secrets out of source control: dotnet user-secrets set "LumoAuth:ApiKey" "lmk_..."
in development, environment variables (LUMOAUTH_API_KEY, LumoAuth__Login__ClientSecret)
in production. Every LumoAuth:* key has an environment-variable fallback.
Use it
using System.Security.Claims;
using LumoAuth.AspNetCore;
using LumoAuth.AspNetCore.Authentication;
using LumoAuth.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddLumoAuth(builder.Configuration); // LumoAuthClient + ILumoAuthorization + [Require*] policies
builder.Services.AddLumoAuthWebAppAuthentication(builder.Configuration) // cookie session + OpenID Connect sign-in (LumoAuth:Login)
.AddLumoAuthBearer(); // and LumoAuth bearer tokens on the same app
builder.Services.AddAuthorization();
builder.Services.AddHealthChecks().AddLumoAuth();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => "home");
// Browser: an unauthenticated visit redirects to LumoAuth and comes back signed in.
app.MapGet("/dashboard", (ClaimsPrincipal user) => $"Hello {user.FindFirst("name")?.Value ?? user.Identity!.Name}")
.RequireAuthorization();
// API: Authorization: Bearer <LumoAuth access token>
app.MapGet("/api/me", (ClaimsPrincipal user) => new { sub = user.GetLumoAuthSubject(), roles = user.FindAll("roles").Select(c => c.Value) })
.RequireAuthorization(new Microsoft.AspNetCore.Authorization.AuthorizeAttribute { AuthenticationSchemes = LumoAuthDefaults.BearerScheme });
// Permission checks run live against LumoAuth, as the caller.
app.MapPost("/invoices/{id}/approve", (string id) => Results.Ok($"approved {id}"))
.RequirePermission("invoice.approve");
app.MapGet("/documents/{id}", (string id) => Results.Ok($"document {id}"))
.RequireRelation("viewer", "document:{id}");
app.MapDelete("/documents/{id}", async (string id, ILumoAuthorization authz) =>
await authz.IsOwnerAsync($"document:{id}") ? Results.NoContent() : Results.Forbid());
app.MapGet("/logout", (HttpContext context) => context.SignOutAsync());
app.MapHealthChecks("/health");
app.Run();
In MVC controllers the same guards are attributes:
[RequirePermission("document.edit")]
public IActionResult Edit(string id) { ... }
[RequirePermission("document.edit", "document.publish", Mode = RequirementMode.Any)]
public IActionResult Publish(string id) { ... }
[RequireAbac("document", "delete", "{id}")]
public IActionResult Delete(string id) { ... }
Run it
dotnet run
https://localhost:5001/dashboardredirects to LumoAuth, then greets you.curl -H "Authorization: Bearer $TOKEN" https://localhost:5001/api/mereturns the token's subject and roles.curl -X POST -H "Authorization: Bearer $TOKEN" https://localhost:5001/invoices/42/approveis 200 when the user holdsinvoice.approve, 403 otherwise.https://localhost:5001/healthreportsHealthywhile the instance answers.
Without ASP.NET Core
The LumoAuth package alone serves workers, console apps and agents:
var lumo = LumoAuthClient.FromEnvironment(); // LUMOAUTH_URL, LUMOAUTH_ORG_ID, LUMOAUTH_API_KEY
bool ok = await lumo.Permissions.CheckAsync("document.edit", CheckOptions.ForUser(userId));
var agent = LumoAgent.FromEnvironment(); // AGENT_CLIENT_ID, AGENT_CLIENT_SECRET
if (await agent.IsAllowedAsync("send_email", new { to = "cfo@acme.com" })) { ... }
For sign-in outside the OpenID Connect handler, LumoAuth.Web.AuthorizationCodeFlow
runs the authorization-code + PKCE flow against any session store.
Next steps
- SDK overview: every namespace, the error taxonomy, the raw-request escape hatch
- AI agent + MCP in five minutes with
LumoAgent,JitContextand approvals - Agent security: AAuth keys, signed HTTP requests and proof-of-possession verification
Standards used on this page
| Plain name | Standard |
|---|---|
| Signed HTTP requests (HTTP message signatures) | RFC 9421 |
See the standards reference for what each one covers and how LumoAuth uses it.