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 groups.

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 VoidResult<ForbiddenError> CreateOrder(CreateOrderRequest request)
{
var userId = currentUser.Id;
var tenantId = currentUser.TenantId;
if (!currentUser.Authorization.HasPermission("orders.create"))
return ForbiddenError.MissingPermission("orders.create");
// ...
return VoidResult<ForbiddenError>.Success();
}
}
Package Role
Pragmatic.Identity SystemUser, identity options, claim mapping; no ASP.NET Core dependency
Pragmatic.Identity.AspNetCore ClaimsPrincipal → ICurrentUser, header-based development identity
Pragmatic.Identity.Local Self-contained local identity: signup, login, password reset (LocalIdentityPackage)
Pragmatic.Identity.Local.Jwt JWT issuing and bearer authentication: UseJwtAuthentication()
Pragmatic.Identity.Oidc Bearer tokens from any external OpenID Connect provider: UseOidcAuthentication()
Pragmatic.Identity.Keycloak Keycloak realm roles, plus an admin client for provisioning: UseKeycloakAuthentication()
Pragmatic.Identity.Persistence EF Core stores for roles, groups and permissions, with temporal assignments
Pragmatic.Identity.Auditing Failed logins and lockouts on the Audit trail, pseudonymised: AddIdentitySecurityAuditing()

ICurrentUser itself lives in Pragmatic.Abstractions, so a library can consume it without any of these.

Terminal window
dotnet add package Pragmatic.Identity
dotnet add package Pragmatic.Identity.Local.Jwt # optional: JWT authentication
// JWT from the Jwt section of the configuration: Key, Issuer, Audience
app.UseJwtAuthentication();
// 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.
  • Users: a plain entity marked [PragmaticUser]; the generator owns its identity members and EF configuration.
  • Persistence: EF stores for roles, groups and permissions, with temporal assignments. There is no JIT provisioning: creating a local record on first external login is not implemented (see Persistence).
  • Authorization integration: feeds Authorization’s permission resolution.

Functional within 1.0.0-alpha: ICurrentUser, local identity, JWT, and EF-backed persistence. See the roadmap.

| Concepts | ICurrentUser model, claim mapping, accessors, the permission chain | | Getting Started | Wire authentication, consume the current user | | Packages | The core 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, external identities, [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).