Elarion
Core Concepts

Current user

ICurrentUser gives handlers transport-neutral access to the authenticated user, without depending on HttpContext.

Handlers often need to know who is calling — for authorization, auditing, or user-scoped caching. Elarion exposes this through a transport-neutral ICurrentUser abstraction so application code never depends on HttpContext or IHttpContextAccessor.

This follows the framework's boundary rule: Elarion owns the abstraction; Elarion.AspNetCore owns the HTTP integration that fills it in.

The abstraction

namespace Elarion.Abstractions.Identity;

public interface ICurrentUser {
    string UserId { get; }
    string? Email { get; }
    IReadOnlyList<string> Roles { get; }
    bool IsAuthenticated { get; }
    bool IsInRole(string role);
}

Inject it like any other service:

[Service]
public sealed class AuditTrail(ICurrentUser user) {
    public AuditEntry Record(string action) =>
        new(action, user.UserId, DateTimeOffset.UtcNow);
}

Wiring it in an ASP.NET Core host

The default implementation reads claims from the authenticated principal into a scoped snapshot. Register it during service configuration and add the middleware after authentication:

builder.Services.AddElarionCurrentUser();

var app = builder.Build();

app.UseAuthentication();
app.UseElarionCurrentUser();   // after authentication, before endpoints
app.UseAuthorization();

UseElarionCurrentUser() copies claim values into a scoped CurrentUserSnapshot once per request. Application handlers then read the snapshot, so they never touch HttpContext and stay testable — in a unit test you simply register a fake ICurrentUser.

Mapping claims

By default the middleware maps standard claim types. Override them when your identity provider uses different ones:

builder.Services.AddElarionCurrentUser(options => {
    options.UserIdClaimType = "sub";
    options.EmailClaimType = "email";
    options.RoleClaimType = ClaimTypes.Role;
    options.DefaultRolesWhenAuthenticated = ["user"];
});
OptionDefaultPurpose
UserIdClaimType"sub"Claim used for UserId.
EmailClaimType"email"Claim used for Email.
RoleClaimTypeClaimTypes.RoleClaim used to populate Roles.
DefaultRolesWhenAuthenticatedemptyRoles granted to any authenticated principal.

Relationship to caching

CurrentUser-scoped caching depends on this abstraction: the cache uses ICurrentUser.UserId (hashed) to isolate entries per user. If you use CurrentUser scope, make sure AddElarionCurrentUser() and UseElarionCurrentUser() are wired and the principal carries a user id claim.

On this page