Skip to content

Pragmatic.Identity

Identity and authentication for the Pragmatic.Design ecosystem — a structured ICurrentUser that works in HTTP requests, background jobs, and tests, layering up to database-backed identity with temporal roles and JIT provisioning.

ASP.NET Core’s ClaimsPrincipal is a transport object, not a domain abstraction. Every service that needs the current user repeats the same pattern: resolve IHttpContextAccessor, null-check HttpContext, navigate claims with magic-string URIs, and special-case each provider. Background jobs have no HttpContext at all, so the whole pattern fails outside HTTP.

// Without Pragmatic.Identity: magic strings, fragile, HTTP-only
var userId = principal?.FindFirst("sub")?.Value
?? principal?.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;

Replace ClaimsPrincipal with a structured ICurrentUser (identity + authorization + authentication sub-objects). Claim mapping is centralized and configurable; the same code runs across HTTP (ClaimsPrincipalUserAccessor), background jobs (SystemUser), and tests — unchanged. Dev vs production auth switches by configuration (HTTP headers in dev, JWT in production).

public class OrderService(ICurrentUser currentUser)
{
public Result CreateOrder(CreateOrderRequest request)
{
var userId = currentUser.Id;
var tenantId = currentUser.TenantId;
if (!currentUser.Authorization.HasPermission("orders.create"))
return Result.Failure(new ForbiddenError());
// ...
}
}
PackageRole
Pragmatic.IdentityICurrentUser, claim mapping, accessors (HTTP / system / test)
Pragmatic.Identity.LocalSelf-contained local identity: signup, login, password reset
Pragmatic.Identity.Local.JwtJWT bearer authentication
Pragmatic.Identity.PersistenceEF-backed identity stores, temporal roles, JIT provisioning
Terminal window
dotnet add package Pragmatic.Identity
dotnet add package Pragmatic.Identity.Local.Jwt # optional: JWT authentication
// config-driven auth: JWT when a signing key is present, NoOp header-auth otherwise
app.UseJwtAuthentication(jwt => jwt.SigningKey = app.Configuration["Jwt:Key"]!);
// consume the current user anywhere — no IHttpContextAccessor, no magic strings
public class Handler(ICurrentUser user) { /* user.Id, user.TenantId, user.Authorization.HasPermission(...) */ }

Full walkthrough: Getting Started.

  • ICurrentUser — identity, authorization, authentication sub-objects; multi-value claims, tenant, impersonation; works in HTTP, jobs, and tests.
  • Local identity — signup/login/password-reset actions (Pragmatic.Identity.Local).
  • JWT — bearer authentication with configurable issuer/audience/expiry.
  • Persistence — EF stores, temporal roles, SCIM-aware JIT provisioning, [PragmaticUser] generation.
  • Authorization integration — feeds Authorization’s permission resolution.

ICurrentUser, local identity, JWT, and EF-backed persistence are functional within the 0.8 preview. See the roadmap.

| Concepts | ICurrentUser model, claim mapping, accessors, the permission chain | | Getting Started | Wire authentication, consume the current user | | Packages | The five packages and how they layer | | JWT Authentication | Bearer tokens, issuer/audience/expiry, signing keys | | Dev Authentication | Header-based auth for development and tests | | Persistence | EF stores, temporal roles, JIT provisioning, [PragmaticUser] | | Common Mistakes | The most frequent identity pitfalls | | Troubleshooting | Problem/solution guide |

  • .NET 10.0+

Part of the Pragmatic.Design ecosystem — see Licensing. Pragmatic.Identity is licensed under the PolyForm Small Business 1.0.0 license (free for small businesses; commercial license above the threshold).