API reference — HTTP & endpoints
Nuvora.Nexus.Sentinel.AspNetCore
ASP.NET Core surface for Sentinel: the "Sentinel" authentication handler (Bearer + httpOnly cookie with CSRF double-submit), the request principal/context accessor, and mountable minimal-API endpoint groups (MapSentinelAuth, MapSentinelProfile).
dotnet add package Nuvora.Nexus.Sentinel.AspNetCore
Nuvora.Nexus.Sentinel.AspNetCore
ISentinelContextAccessor
public interface ISentinelContextAccessor
DI-friendly view of the current request’s Sentinel identity for services that should not take an HttpContext dependency directly.
Properties
SentinelPrincipal? Principal { get; }
SubjectSnapshot? Snapshot { get; }
SentinelAspNetOptions
public sealed class SentinelAspNetOptions
The single options class for the whole ASP.NET surface (deliverable folds endpoint options in here on purpose — one class to configure, one source of truth): token validation identity for the authentication handler, transport selection, and cookie naming/pathing.
Properties
Guid DefaultRealmId { get; set; }
Realm the auth endpoints serve. This wave hosts a single realm per mounted group; multi-realm routing is the reference server’s job and layers on top later.
List<string> AllowedFederationReturnUrls { get; set; }
Allowlist for the federation return URL: the redirect_uri a caller hands to /auth/idp/{key}/start, where the BROWSER lands after the federated login completes (distinct from the OAuth callback, which is always Sentinel’s own endpoint). Site-relative paths (/app, but never protocol-relative //…) are always allowed; absolute URLs must match an entry here — exact, or a single-* wildcard with WorkloadWildcard semantics (https://app.example.com/*). Empty list = absolute return URLs are refused (fail-closed against open redirects).
SentinelTokenTransport Transport { get; set; }
Response mode for /login, /mfa/verify and /refresh successes.
string AccessTokenCookieName { get; set; }
httpOnly access-token cookie.
string Audience { get; set; }
The aud this host mints into and accepts from access tokens. Audience enforcement is not optional — an empty value fails validation rather than skipping the check.
string CookiePath { get; set; }
Path for the access-token and CSRF cookies, relative to the host’s PathBase. Cookie paths are always combined with the request’s PathBase at set time — never hardcoded — which fixes the Node stack’s hardcoded /auth that broke any host mounted under a sub-path.
string CsrfCookieName { get; set; }
NON-httpOnly CSRF cookie for the double-submit check: client script must be able to read it to echo it in the header.
string CsrfHeaderName { get; set; }
Header that must carry the SentinelAspNetOptions.CsrfCookieName value on unsafe cookie-authenticated requests.
string Issuer { get; set; }
Expected iss of access tokens. Must equal SentinelTokenOptions.Issuer used at minting.
string RefreshTokenCookieName { get; set; }
httpOnly refresh-token cookie; scoped to the refresh endpoint path only, so it never rides along on ordinary requests.
SentinelContextAccessor
public sealed class SentinelContextAccessor : ISentinelContextAccessor
Scoped accessor backed by IHttpContextAccessor; registered by AddSentinelAuthentication.
Constructors
SentinelContextAccessor(IHttpContextAccessor httpContextAccessor)
Scoped accessor backed by IHttpContextAccessor; registered by AddSentinelAuthentication.
Properties
SentinelPrincipal? Principal { get; }
SubjectSnapshot? Snapshot { get; }
SentinelHttpContextExtensions
public static class SentinelHttpContextExtensions
Methods
static SentinelPrincipal? GetSentinelPrincipal(this HttpContext context)
The Sentinel principal for this request, or null when the request is unauthenticated.
static SubjectSnapshot? GetSentinelSnapshot(this HttpContext context)
The subject snapshot resolved at authentication time (grants + team memberships), or null when unauthenticated or no snapshot source is wired.
SentinelHttpContextKeys
public static class SentinelHttpContextKeys
Keys under which the handler stashes per-request state in HttpContext.Items.
Fields
const string Principal = "Nuvora.Nexus.Sentinel.Principal"
const string Snapshot = "Nuvora.Nexus.Sentinel.Snapshot"
The subject’s permission snapshot, teams included (the Node bug of hardcoded-empty team memberships is fixed by populating this at authentication time).
SentinelPrincipal
public sealed record SentinelPrincipal : IEquatable<SentinelPrincipal>
The authenticated request identity Sentinel establishes: who, in which realm/org context, from which session, at what MFA level. Stored in HttpContext.Items by the authentication handler and read through SentinelHttpContextExtensions.GetSentinelPrincipal or ISentinelContextAccessor.
SentinelPrincipal.OwnerUserId is the attribution split: for API-key requests, SentinelPrincipal.SubjectId is the CREDENTIAL (the key’s id — the authorization context), while SentinelPrincipal.OwnerUserId is the HUMAN whose snapshot caps the key — audit and attribution read this one. Null for user principals, where subject and owner coincide.
Constructors
SentinelPrincipal(Guid SubjectId, Guid RealmId, Guid? OrganizationId, Guid? SessionId, SessionMfaLevel MfaLevel, SentinelPrincipalKind Kind, Guid? OwnerUserId = null)
The authenticated request identity Sentinel establishes: who, in which realm/org context, from which session, at what MFA level. Stored in HttpContext.Items by the authentication handler and read through SentinelHttpContextExtensions.GetSentinelPrincipal or ISentinelContextAccessor. SentinelPrincipal.OwnerUserId is the attribution split: for API-key requests, SentinelPrincipal.SubjectId is the CREDENTIAL (the key’s id — the authorization context), while SentinelPrincipal.OwnerUserId is the HUMAN whose snapshot caps the key — audit and attribution read this one. Null for user principals, where subject and owner coincide.
Properties
Guid RealmId { get; init; }
Guid SubjectId { get; init; }
Guid? ImpersonationId { get; init; }
The impersonation record id (imp_id claim) backing the impersonation banner contract; null when not impersonated.
Guid? ImpersonatorId { get; init; }
The impersonating admin’s user id when this request rides an impersonation token — the token’s act.sub. SentinelPrincipal.SubjectId is then the TARGET (authorization runs as the target); this is the true attribution. Null when not impersonated.
Guid? OrganizationId { get; init; }
Guid? OwnerUserId { get; init; }
Guid? SessionId { get; init; }
SentinelPrincipalKind Kind { get; init; }
SessionMfaLevel MfaLevel { get; init; }
SentinelPrincipalKind
public enum SentinelPrincipalKind
What kind of credential established the request identity. SentinelPrincipalKind.User and SentinelPrincipalKind.ApiKey ship now; SentinelPrincipalKind.ServiceAccount principals arrive with the OIDC client-credentials grant (Wave 3).
Values
UserApiKeyServiceAccount
SentinelTokenTransport
public enum SentinelTokenTransport
How successful auth-flow responses hand tokens back to the client (both transports are first-class; cookie-first is the guidance for browser apps, Bearer for APIs, machines, and mobile).
Values
BearerAndCookie— Set cookies AND return tokens in the JSON body. The permissive default: one host serves browser and API clients alike.Bearer— Tokens only in the JSON body; no cookies are set.Cookie— Tokens only in httpOnly cookies; the JSON body never carries them (browser apps that must keep tokens out of script reach).
Nuvora.Nexus.Sentinel.AspNetCore.Authentication
SentinelAuthenticationDefaults
public static class SentinelAuthenticationDefaults
Fields
const string Scheme = "Sentinel"
The scheme name registered by AddSentinelAuthentication.
SentinelAuthenticationHandler
public sealed class SentinelAuthenticationHandler : AuthenticationHandler<SentinelAuthenticationOptions>
Establishes the Sentinel principal from either transport, in order: (a) Authorization: Bearer header, (b) the access-token cookie. The cookie path additionally enforces CSRF double-submit on unsafe methods. Token validation is the strict Core path — typ at+sentinel, issuer, audience, all mandatory — with keys resolved through the realm’s SigningKeyRing.
Constructors
SentinelAuthenticationHandler(IOptionsMonitor<SentinelAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IOptions<SentinelAspNetOptions> sentinelOptions, SigningKeyRing keyRing, ISentinelClock clock)
Establishes the Sentinel principal from either transport, in order: (a) Authorization: Bearer header, (b) the access-token cookie. The cookie path additionally enforces CSRF double-submit on unsafe methods. Token validation is the strict Core path — typ at+sentinel, issuer, audience, all mandatory — with keys resolved through the realm’s SigningKeyRing.
Methods
override Task<AuthenticateResult> HandleAuthenticateAsync()
Allows derived types to handle authentication.
SentinelAuthenticationOptions
public sealed class SentinelAuthenticationOptions : AuthenticationSchemeOptions
Scheme options exist only because AuthenticationHandler requires a per-scheme options type. All real configuration lives in SentinelAspNetOptions — deliberately one options class for the whole surface, not two half-overlapping ones.
Nuvora.Nexus.Sentinel.AspNetCore.Captcha
HCaptchaVerifier
public sealed class HCaptchaVerifier : SiteVerifyCaptchaVerifier
hCaptcha.
Constructors
HCaptchaVerifier(IHttpClientFactory httpClientFactory, SentinelCaptchaOptions options)
hCaptcha.
ReCaptchaVerifier
public sealed class ReCaptchaVerifier : SiteVerifyCaptchaVerifier
Google reCAPTCHA v2/v3. v3 score thresholds are the host’s concern — this adapter honors the boolean verdict.
Constructors
ReCaptchaVerifier(IHttpClientFactory httpClientFactory, SentinelCaptchaOptions options)
Google reCAPTCHA v2/v3. v3 score thresholds are the host’s concern — this adapter honors the boolean verdict.
SiteVerifyCaptchaVerifier
public abstract class SiteVerifyCaptchaVerifier : ICaptchaVerifier
Shared implementation for the three supported CAPTCHA providers — Turnstile, hCaptcha and reCAPTCHA all expose the same “siteverify” contract: form-encoded POST of secret/response/remoteip, JSON reply with a boolean success. Only the endpoint URL differs, so each provider is a one-line subclass.
Failure posture per the ICaptchaVerifier contract: malformed tokens, non-2xx replies, timeouts and provider outages all return false — an unverifiable token is an unverified token. That is safe because the adaptive-captcha band sits BELOW the hard block threshold: the worst a provider outage causes is a challenge loop at elevated traffic, never a lockout.
Constructors
SiteVerifyCaptchaVerifier(IHttpClientFactory httpClientFactory, SentinelCaptchaOptions options, string verifyEndpoint)
Shared implementation for the three supported CAPTCHA providers — Turnstile, hCaptcha and reCAPTCHA all expose the same “siteverify” contract: form-encoded POST of secret/response/remoteip, JSON reply with a boolean success. Only the endpoint URL differs, so each provider is a one-line subclass. Failure posture per the ICaptchaVerifier contract: malformed tokens, non-2xx replies, timeouts and provider outages all return false — an unverifiable token is an unverified token. That is safe because the adaptive-captcha band sits BELOW the hard block threshold: the worst a provider outage causes is a challenge loop at elevated traffic, never a lockout.
Methods
ValueTask<bool> VerifyAsync(string token, string? ip, CancellationToken cancellationToken = default(CancellationToken))
Fields
const string HttpClientName = "sentinel-captcha"
Named client so hosts can attach their own handlers/timeouts via AddHttpClient(HttpClientName).
TurnstileCaptchaVerifier
public sealed class TurnstileCaptchaVerifier : SiteVerifyCaptchaVerifier
Cloudflare Turnstile — the default provider.
Constructors
TurnstileCaptchaVerifier(IHttpClientFactory httpClientFactory, SentinelCaptchaOptions options)
Cloudflare Turnstile — the default provider.
Nuvora.Nexus.Sentinel.AspNetCore.DependencyInjection
SentinelAspNetCoreServiceCollectionExtensions
public static class SentinelAspNetCoreServiceCollectionExtensions
Methods
static IServiceCollection AddSentinelAuthentication(this IServiceCollection services, Action<SentinelAspNetOptions>? configure = null)
Registers the “Sentinel” authentication scheme plus the request-context accessor. The scheme is also made the default authenticate/challenge scheme so app.UseAuthentication() runs the handler without further ceremony; hosts that compose multiple schemes can override the defaults through their own AddAuthentication call (registration is additive, same posture as AddSentinel). The handler resolves SigningKeyRing and ISentinelClock from DI — the host (or the meta package wiring) must have registered an initialized ring for the realm.
SentinelCaptchaServiceCollectionExtensions
public static class SentinelCaptchaServiceCollectionExtensions
Methods
static IServiceCollection AddSentinelCaptcha(this IServiceCollection services, Action<SentinelCaptchaOptions> configure)
Registers the adaptive-CAPTCHA verifier for the configured provider — Turnstile, hCaptcha or reCAPTCHA, all speaking the same siteverify shape. Additive and TryAdd-based like every other AddSentinel* call; a host’s own ICaptchaVerifier registered earlier wins. This wires VERIFICATION only. The escalation itself is switched on the abuse options — set SentinelAbuseOptions.CaptchaEnabled (with its SentinelAbuseOptions.CaptchaFactor band) when registering them, so the challenge is only ever demanded where a provider exists to verify it.
SentinelFederationServiceCollectionExtensions
public static class SentinelFederationServiceCollectionExtensions
Registration for the inbound-federation surface, following the standard Sentinel DI conventions (TryAdd, host wins).
Methods
static IServiceCollection AddSentinelFederation(this IServiceCollection services, Action<FederatedLoginOptions>? configure = null)
Registers FederatedLoginService and its collaborators: IHttpClientFactory-backed implementations of the two HTTP ports (IFederationTokenClient for the code exchange, IRemoteJwksCache for discovery/JWKS — Core stays HTTP-free), the in-memory challenge/state stores (hot state), an in-memory IIdentityProviderStore default (acceptable: an empty provider registry denies every federated login — fail-closed), and the PasskeyLoginCompleter completion seam. What is NOT defaulted: IFederatedIdentityStore — federated links and JIT users are identity data, and the same footgun rationale as the user/session stores applies: register a store adapter (AddSentinelEfFederationStores) or an in-memory instance explicitly, BEFORE this call so the TryAdd defaults yield. Call alongside AddSentinel() + AddSentinelAuthentication(), then mount with MapSentinelFederation().
Fields
const string FederationHttpClientName = "SentinelFederation"
Named HttpClient used for token-endpoint, JWKS and discovery fetches, so hosts can configure it (proxy, timeouts) by name.
SentinelPasskeyServiceCollectionExtensions
public static class SentinelPasskeyServiceCollectionExtensions
Methods
static IServiceCollection AddSentinelPasskeys(this IServiceCollection services, Action<SentinelPasskeyOptions> configure)
Registers the passkey/WebAuthn stack: SentinelPasskeyOptions, the ceremony service, and the framework-free login completer. Additive and idempotent like AddSentinel. What is NOT defaulted: IPasskeyStore — passkeys are identity data, and the same footgun rationale as the user/session stores applies: register a store adapter or opt into InMemoryPasskeyStore explicitly. IChallengeStore gets the in-memory single-node default (hot state, same posture as the rate counters); fleet deployments register the ValKey adapter.
Nuvora.Nexus.Sentinel.AspNetCore.Endpoints
AddDomainRequest
public sealed record AddDomainRequest : IEquatable<AddDomainRequest>
Kind: “emailDomain” (default) or “subdomain”.
Constructors
AddDomainRequest(string? Domain, string? Kind = null, bool Verified = false)
Kind: “emailDomain” (default) or “subdomain”.
Properties
bool Verified { get; init; }
string? Domain { get; init; }
string? Kind { get; init; }
AdminPageResponse<T>
public sealed record AdminPageResponse<T> : IEquatable<AdminPageResponse<T>>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
AdminPageResponse(IReadOnlyList<T> Items, int Offset, int Limit, int Total)
Properties
IReadOnlyList<T> Items { get; init; }
int Limit { get; init; }
int Offset { get; init; }
int Total { get; init; }
AdminUserView
public sealed record AdminUserView : IEquatable<AdminUserView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
AdminUserView(Guid Id, string Email, string? DisplayName, string Status, bool EmailVerified, DateTimeOffset CreatedAt, DateTimeOffset? LastLoginAt)
Properties
DateTimeOffset CreatedAt { get; init; }
DateTimeOffset? LastLoginAt { get; init; }
Guid Id { get; init; }
bool EmailVerified { get; init; }
string Email { get; init; }
string Status { get; init; }
string? DisplayName { get; init; }
ApproveImpersonationRequest
public sealed record ApproveImpersonationRequest : IEquatable<ApproveImpersonationRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ApproveImpersonationRequest(string? Token)
Properties
string? Token { get; init; }
AssignRoleRequest
public sealed record AssignRoleRequest : IEquatable<AssignRoleRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
AssignRoleRequest(Guid? UserId, Guid? OrganizationId)
Properties
Guid? OrganizationId { get; init; }
Guid? UserId { get; init; }
AuditEntryView
public sealed record AuditEntryView : IEquatable<AuditEntryView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
AuditEntryView(long Sequence, Guid ActorId, string ActorKind, string Action, string TargetKind, Guid? TargetId, Guid? OrganizationId, string? Before, string? After, DateTimeOffset OccurredAt, string PreviousHash, string EntryHash)
Properties
DateTimeOffset OccurredAt { get; init; }
Guid ActorId { get; init; }
Guid? OrganizationId { get; init; }
Guid? TargetId { get; init; }
long Sequence { get; init; }
string Action { get; init; }
string ActorKind { get; init; }
string EntryHash { get; init; }
string PreviousHash { get; init; }
string TargetKind { get; init; }
string? After { get; init; }
string? Before { get; init; }
AuditPageResponse
public sealed record AuditPageResponse : IEquatable<AuditPageResponse>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
AuditPageResponse(IReadOnlyList<AuditEntryView> Entries, bool ChainIntact, long? FirstBrokenSequence)
Properties
IReadOnlyList<AuditEntryView> Entries { get; init; }
bool ChainIntact { get; init; }
long? FirstBrokenSequence { get; init; }
BreakGlassStatusView
public sealed record BreakGlassStatusView : IEquatable<BreakGlassStatusView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
BreakGlassStatusView(Guid RealmId, DateTimeOffset? LastDrillAt, DateTimeOffset? LastUseAt, bool DrillStale, int DrillIntervalDays)
Properties
DateTimeOffset? LastDrillAt { get; init; }
DateTimeOffset? LastUseAt { get; init; }
Guid RealmId { get; init; }
bool DrillStale { get; init; }
int DrillIntervalDays { get; init; }
CreateOrganizationRequest
public sealed record CreateOrganizationRequest : IEquatable<CreateOrganizationRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
CreateOrganizationRequest(string? Key, string? DisplayName)
Properties
string? DisplayName { get; init; }
string? Key { get; init; }
CreateRealmRequest
public sealed record CreateRealmRequest : IEquatable<CreateRealmRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
CreateRealmRequest(string? Key, string? DisplayName, bool IsDefault = false)
Properties
bool IsDefault { get; init; }
string? DisplayName { get; init; }
string? Key { get; init; }
CreateRoleRequest
public sealed record CreateRoleRequest : IEquatable<CreateRoleRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
CreateRoleRequest(Guid? OrganizationId, string? Key, string? DisplayName, List<GrantRequest>? Grants)
Properties
Guid? OrganizationId { get; init; }
List<GrantRequest>? Grants { get; init; }
string? DisplayName { get; init; }
string? Key { get; init; }
CreateWebhookEndpointRequest
public sealed record CreateWebhookEndpointRequest : IEquatable<CreateWebhookEndpointRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
CreateWebhookEndpointRequest(Guid? OrganizationId, string? Url, List<string>? EventKinds)
Properties
Guid? OrganizationId { get; init; }
List<string>? EventKinds { get; init; }
string? Url { get; init; }
DomainView
public sealed record DomainView : IEquatable<DomainView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
DomainView(Guid Id, Guid OrganizationId, string Value, string Kind, bool Verified)
Properties
Guid Id { get; init; }
Guid OrganizationId { get; init; }
bool Verified { get; init; }
string Kind { get; init; }
string Value { get; init; }
EraseUserRequest
public sealed record EraseUserRequest : IEquatable<EraseUserRequest>
Erasure confirmation body: the literal string "erase", so the irreversible call can never be a stray POST.
Constructors
EraseUserRequest(string? Confirm)
Erasure confirmation body: the literal string "erase", so the irreversible call can never be a stray POST.
Properties
string? Confirm { get; init; }
FederationDiscoverRequest
public sealed record FederationDiscoverRequest : IEquatable<FederationDiscoverRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
FederationDiscoverRequest(string? Email)
Properties
string? Email { get; init; }
FederationDiscoverResponse
public sealed record FederationDiscoverResponse : IEquatable<FederationDiscoverResponse>
Discovery hints. ALWAYS 200 with possibly-null fields: an unknown domain, an unrouted one, and a malformed email are indistinguishable on the wire — the endpoint reads only the org-domain registry, never the user table, so it cannot leak who exists.
Constructors
FederationDiscoverResponse(Guid? OrganizationId, string? IdentityProviderKey)
Discovery hints. ALWAYS 200 with possibly-null fields: an unknown domain, an unrouted one, and a malformed email are indistinguishable on the wire — the endpoint reads only the org-domain registry, never the user table, so it cannot leak who exists.
Properties
Guid? OrganizationId { get; init; }
string? IdentityProviderKey { get; init; }
GrantRequest
public sealed record GrantRequest : IEquatable<GrantRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
GrantRequest(string? Pattern, string? Effect, Guid? OrganizationId, List<Guid>? TeamIds, string? ConditionJson)
Properties
Guid? OrganizationId { get; init; }
List<Guid>? TeamIds { get; init; }
string? ConditionJson { get; init; }
string? Effect { get; init; }
string? Pattern { get; init; }
GrantView
public sealed record GrantView : IEquatable<GrantView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
GrantView(Guid Id, string Pattern, string Effect, Guid? OrganizationId, IReadOnlyList<Guid>? TeamIds, string? ConditionJson)
Properties
Guid Id { get; init; }
Guid? OrganizationId { get; init; }
IReadOnlyList<Guid>? TeamIds { get; init; }
string Effect { get; init; }
string Pattern { get; init; }
string? ConditionJson { get; init; }
ImpersonationBanner
public sealed record ImpersonationBanner : IEquatable<ImpersonationBanner>
The impersonation banner contract: present on /profile/me exactly when the request rides an impersonation token. Clients render “you are being impersonated / you are impersonating” off this block — actorId is the impersonating admin, expiresAt the time-box end (null only if the impersonation record is no longer resolvable).
Constructors
ImpersonationBanner(Guid ActorId, DateTimeOffset? ExpiresAt)
The impersonation banner contract: present on /profile/me exactly when the request rides an impersonation token. Clients render “you are being impersonated / you are impersonating” off this block — actorId is the impersonating admin, expiresAt the time-box end (null only if the impersonation record is no longer resolvable).
Properties
DateTimeOffset? ExpiresAt { get; init; }
Guid ActorId { get; init; }
ImpersonationResponse
public sealed record ImpersonationResponse : IEquatable<ImpersonationResponse>
AccessToken is the impersonation access token; null while consent is pending.
Constructors
ImpersonationResponse(ImpersonationView Impersonation, string? AccessToken)
AccessToken is the impersonation access token; null while consent is pending.
Properties
ImpersonationView Impersonation { get; init; }
string? AccessToken { get; init; }
ImpersonationView
public sealed record ImpersonationView : IEquatable<ImpersonationView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ImpersonationView(Guid Id, Guid ActorUserId, Guid TargetUserId, Guid? OrganizationId, string Reason, string Status, DateTimeOffset? StartedAt, DateTimeOffset ExpiresAt, DateTimeOffset? EndedAt)
Properties
DateTimeOffset ExpiresAt { get; init; }
DateTimeOffset? EndedAt { get; init; }
DateTimeOffset? StartedAt { get; init; }
Guid ActorUserId { get; init; }
Guid Id { get; init; }
Guid TargetUserId { get; init; }
Guid? OrganizationId { get; init; }
string Reason { get; init; }
string Status { get; init; }
InspectRequest
public sealed record InspectRequest : IEquatable<InspectRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
InspectRequest(Guid? SubjectId, Guid? OrganizationId, string? Permission, Guid? ResourceOrgId, Guid? ResourceOwnerId, List<Guid>? Teams, Dictionary<string, JsonElement>? Attributes)
Properties
Dictionary<string, JsonElement>? Attributes { get; init; }
Guid? OrganizationId { get; init; }
Guid? ResourceOrgId { get; init; }
Guid? ResourceOwnerId { get; init; }
Guid? SubjectId { get; init; }
List<Guid>? Teams { get; init; }
string? Permission { get; init; }
InvitationAcceptRequest
public sealed record InvitationAcceptRequest : IEquatable<InvitationAcceptRequest>
Invitation acceptance: the single-use invite token plus the invitee’s chosen first password.
Constructors
InvitationAcceptRequest(string? Token, string? Password)
Invitation acceptance: the single-use invite token plus the invitee’s chosen first password.
Properties
string? Password { get; init; }
string? Token { get; init; }
InvitationView
public sealed record InvitationView : IEquatable<InvitationView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
InvitationView(Guid UserId, string Token, DateTimeOffset ExpiresAt, string AcceptPath)
Properties
DateTimeOffset ExpiresAt { get; init; }
Guid UserId { get; init; }
string AcceptPath { get; init; }
string Token { get; init; }
LoginRequest
public sealed record LoginRequest : IEquatable<LoginRequest>
DeviceFingerprint is the client’s opaque device hash for the adaptive-risk signals; CaptchaToken carries a solved challenge when a previous attempt answered 429 captcha_required. Both optional and additive — pre-existing clients are untouched.
Constructors
LoginRequest(string? Email, string? Password, Guid? OrganizationId, string? DeviceFingerprint = null, string? CaptchaToken = null)
DeviceFingerprint is the client’s opaque device hash for the adaptive-risk signals; CaptchaToken carries a solved challenge when a previous attempt answered 429 captcha_required. Both optional and additive — pre-existing clients are untouched.
Properties
Guid? OrganizationId { get; init; }
string? CaptchaToken { get; init; }
string? DeviceFingerprint { get; init; }
string? Email { get; init; }
string? Password { get; init; }
MeResponse
public sealed record MeResponse : IEquatable<MeResponse>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
MeResponse(Guid Id, string Email, string? DisplayName, bool EmailVerified, IReadOnlyList<Guid> OrganizationIds, ImpersonationBanner? Impersonation = null)
Properties
Guid Id { get; init; }
IReadOnlyList<Guid> OrganizationIds { get; init; }
ImpersonationBanner? Impersonation { get; init; }
bool EmailVerified { get; init; }
string Email { get; init; }
string? DisplayName { get; init; }
MfaRequiredResponse
public sealed record MfaRequiredResponse : IEquatable<MfaRequiredResponse>
First factor passed, second factor pending. Same 200 status as success so proxies/logs can’t fingerprint accounts by MFA enrollment. Factor tells the client what to render: "totp" (authenticator/recovery input) or "email_otp" (a code was mailed — risk step-up fallback).
Constructors
MfaRequiredResponse(string Status, string MfaPendingToken, string? Factor = null)
First factor passed, second factor pending. Same 200 status as success so proxies/logs can’t fingerprint accounts by MFA enrollment. Factor tells the client what to render: "totp" (authenticator/recovery input) or "email_otp" (a code was mailed — risk step-up fallback).
Properties
string MfaPendingToken { get; init; }
string Status { get; init; }
string? Factor { get; init; }
MfaVerifyRequest
public sealed record MfaVerifyRequest : IEquatable<MfaVerifyRequest>
Kind selects the second factor: "totp", "recovery" or "email_otp".
Constructors
MfaVerifyRequest(string? MfaPendingToken, string? Code, string? Kind, string? DeviceFingerprint = null)
Kind selects the second factor: "totp", "recovery" or "email_otp".
Properties
string? Code { get; init; }
string? DeviceFingerprint { get; init; }
string? Kind { get; init; }
string? MfaPendingToken { get; init; }
OidcClientCreatedView
public sealed record OidcClientCreatedView : IEquatable<OidcClientCreatedView>
Secret is present exactly once — on create/rotate of a confidential client.
Constructors
OidcClientCreatedView(OidcClientView Client, string? Secret)
Secret is present exactly once — on create/rotate of a confidential client.
Properties
OidcClientView Client { get; init; }
string? Secret { get; init; }
OidcClientRequest
public sealed record OidcClientRequest : IEquatable<OidcClientRequest>
Type: “confidential” (default) or “public”; Status: “active” (default) or “suspended”.
Constructors
OidcClientRequest(string? ClientId, string? Type, List<string>? RedirectUris = null, List<string>? PostLogoutRedirectUris = null, List<string>? AllowedScopes = null, string? Audience = null, bool RequireConsent = false, bool FirstParty = false, double? AccessTokenLifetimeSeconds = null, string? BackChannelLogoutUri = null, string? Status = null)
Type: “confidential” (default) or “public”; Status: “active” (default) or “suspended”.
Properties
List<string>? AllowedScopes { get; init; }
List<string>? PostLogoutRedirectUris { get; init; }
List<string>? RedirectUris { get; init; }
bool FirstParty { get; init; }
bool RequireConsent { get; init; }
double? AccessTokenLifetimeSeconds { get; init; }
string? Audience { get; init; }
string? BackChannelLogoutUri { get; init; }
string? ClientId { get; init; }
string? Status { get; init; }
string? Type { get; init; }
OidcClientView
public sealed record OidcClientView : IEquatable<OidcClientView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
OidcClientView(Guid Id, string ClientId, string Type, IReadOnlyList<string> RedirectUris, IReadOnlyList<string> PostLogoutRedirectUris, IReadOnlyList<string> AllowedScopes, string? Audience, bool RequireConsent, bool FirstParty, double? AccessTokenLifetimeSeconds, string? BackChannelLogoutUri, string Status, bool HasSecret, DateTimeOffset CreatedAt)
Properties
DateTimeOffset CreatedAt { get; init; }
Guid Id { get; init; }
IReadOnlyList<string> AllowedScopes { get; init; }
IReadOnlyList<string> PostLogoutRedirectUris { get; init; }
IReadOnlyList<string> RedirectUris { get; init; }
bool FirstParty { get; init; }
bool HasSecret { get; init; }
bool RequireConsent { get; init; }
double? AccessTokenLifetimeSeconds { get; init; }
string ClientId { get; init; }
string Status { get; init; }
string Type { get; init; }
string? Audience { get; init; }
string? BackChannelLogoutUri { get; init; }
OrgSwitchRequest
public sealed record OrgSwitchRequest : IEquatable<OrgSwitchRequest>
Org switch: the organization to mint the next token context for.
Constructors
OrgSwitchRequest(Guid? OrganizationId)
Org switch: the organization to mint the next token context for.
Properties
Guid? OrganizationId { get; init; }
OrganizationView
public sealed record OrganizationView : IEquatable<OrganizationView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
OrganizationView(Guid Id, string Key, string DisplayName, string Status, DateTimeOffset CreatedAt)
Properties
DateTimeOffset CreatedAt { get; init; }
Guid Id { get; init; }
string DisplayName { get; init; }
string Key { get; init; }
string Status { get; init; }
PasskeyCredentialView
public sealed record PasskeyCredentialView : IEquatable<PasskeyCredentialView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
PasskeyCredentialView(Guid Id, string CredentialId, string? Label, bool UvCapable, DateTimeOffset CreatedAt, DateTimeOffset? LastUsedAt)
Properties
DateTimeOffset CreatedAt { get; init; }
DateTimeOffset? LastUsedAt { get; init; }
Guid Id { get; init; }
bool UvCapable { get; init; }
string CredentialId { get; init; }
string? Label { get; init; }
PasskeyLoginRequest
public sealed record PasskeyLoginRequest : IEquatable<PasskeyLoginRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
PasskeyLoginRequest(string? CeremonyId, JsonElement? Response, Guid? OrganizationId)
Properties
Guid? OrganizationId { get; init; }
JsonElement? Response { get; init; }
string? CeremonyId { get; init; }
PasskeyMfaVerifyRequest
public sealed record PasskeyMfaVerifyRequest : IEquatable<PasskeyMfaVerifyRequest>
Passkey as second factor: the pending token from the password login plus an assertion.
Constructors
PasskeyMfaVerifyRequest(string? MfaPendingToken, string? CeremonyId, JsonElement? Response)
Passkey as second factor: the pending token from the password login plus an assertion.
Properties
JsonElement? Response { get; init; }
string? CeremonyId { get; init; }
string? MfaPendingToken { get; init; }
PasskeyOptionsResponse
public sealed record PasskeyOptionsResponse : IEquatable<PasskeyOptionsResponse>
Ceremony start response: pass Options to the WebAuthn API, return CeremonyId with the result.
Constructors
PasskeyOptionsResponse(string CeremonyId, JsonElement Options)
Ceremony start response: pass Options to the WebAuthn API, return CeremonyId with the result.
Properties
JsonElement Options { get; init; }
string CeremonyId { get; init; }
PasskeyRegisterRequest
public sealed record PasskeyRegisterRequest : IEquatable<PasskeyRegisterRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
PasskeyRegisterRequest(string? CeremonyId, string? Label, JsonElement? Response)
Properties
JsonElement? Response { get; init; }
string? CeremonyId { get; init; }
string? Label { get; init; }
PasskeyRegisteredResponse
public sealed record PasskeyRegisteredResponse : IEquatable<PasskeyRegisteredResponse>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
PasskeyRegisteredResponse(string Status, Guid Id, string CredentialId, bool UvCapable, string? Label)
Properties
Guid Id { get; init; }
bool UvCapable { get; init; }
string CredentialId { get; init; }
string Status { get; init; }
string? Label { get; init; }
PatternView
public sealed record PatternView : IEquatable<PatternView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
PatternView(string Pattern, string Effect)
Properties
string Effect { get; init; }
string Pattern { get; init; }
PermissionsResponse
public sealed record PermissionsResponse : IEquatable<PermissionsResponse>
Redacted client view of the permission snapshot: allow patterns and team ids only.
Constructors
PermissionsResponse(IReadOnlyList<PatternView> Patterns, IReadOnlyList<Guid> Teams)
Redacted client view of the permission snapshot: allow patterns and team ids only.
Properties
IReadOnlyList<Guid> Teams { get; init; }
IReadOnlyList<PatternView> Patterns { get; init; }
RealmView
public sealed record RealmView : IEquatable<RealmView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
RealmView(Guid Id, string Key, string DisplayName, bool IsDefault, DateTimeOffset CreatedAt)
Properties
DateTimeOffset CreatedAt { get; init; }
Guid Id { get; init; }
bool IsDefault { get; init; }
string DisplayName { get; init; }
string Key { get; init; }
RefreshRequest
public sealed record RefreshRequest : IEquatable<RefreshRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
RefreshRequest(string? RefreshToken)
Properties
string? RefreshToken { get; init; }
RoleView
public sealed record RoleView : IEquatable<RoleView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
RoleView(Guid Id, Guid? OrganizationId, string Key, string DisplayName, bool IsBuiltIn, IReadOnlyList<GrantView>? Grants)
Properties
Guid Id { get; init; }
Guid? OrganizationId { get; init; }
IReadOnlyList<GrantView>? Grants { get; init; }
bool IsBuiltIn { get; init; }
string DisplayName { get; init; }
string Key { get; init; }
SentinelAdminEndpoints
public static class SentinelAdminEndpoints
The delegated-administration endpoint group: realm/org/user/role management, the authz inspector, and the audit ledger.
This layer is deliberately thin: it resolves the CALLER’s snapshot (stashed by the authentication handler) and hands every decision to SentinelAdminService — org fencing lives in the domain layer where the evaluator is the single authority, never in routing. A typed AdminDenied maps to 403 problem+json with the stable code admin_scope; missing targets map to 404; validation failures to 400.
Methods
static RouteGroupBuilder MapSentinelAdmin(this IEndpointRouteBuilder endpoints, string prefix = "/sentinel-admin")
Fields
const string AdminScopeErrorCode = "admin_scope"
Stable machine code for admin scope denials; clients switch on it, renaming is breaking.
SentinelAuthEndpoints
public static class SentinelAuthEndpoints
The authentication flow endpoint group: login, MFA step-up, refresh rotation, logout. Mountable and opt-in — hosts call SentinelAuthEndpoints.MapSentinelAuth where they want the group, nothing is auto-mapped.
Methods
static RouteGroupBuilder MapSentinelAuth(this IEndpointRouteBuilder endpoints, string prefix = "/auth")
Maps POST {prefix}/login, {prefix}/mfa/verify, {prefix}/refresh, {prefix}/org/switch, {prefix}/logout, {prefix}/logout-all. Requires the Core login stack in DI (LoginService, RefreshTokenService, AccessTokenMinter, SigningKeyRing, stores, clock) plus AddSentinelAuthentication for the logout endpoints’ principal.
SentinelBreakGlassEndpoints
public static class SentinelBreakGlassEndpoints
The break-glass admin endpoint group: drill status and the drill marker. Both require sentinel:global:manage — which the break-glass account’s own capped grants (sentinel:global:* by default) satisfy, so the drill can be stamped from the break-glass session itself.
Methods
static RouteGroupBuilder MapSentinelBreakGlass(this IEndpointRouteBuilder endpoints, string prefix = "/sentinel-admin/break-glass")
SentinelEndpointPermissions
public static class SentinelEndpointPermissions
The route-discovery surface: attach metadata at mapping time, validate the mounted set at startup.
Methods
static TBuilder WithSentinelPermission<TBuilder>(this TBuilder builder, string permissionId)
Declares the permission guarding this endpoint (or every endpoint of a group). The id is parsed by the permission-id grammar HERE — a malformed id fails at mapping time, not at scan time.
static Task<IReadOnlyList<string>> ValidateSentinelEndpointPermissionsAsync(this IEndpointRouteBuilder endpoints, CancellationToken cancellationToken = default(CancellationToken))
Route discovery: scans every mounted endpoint for SentinelPermissionMetadata and checks the ids against the definition catalog via DefinitionSyncService.ValidateUsageAsync. Call at startup AFTER definition sync and after mapping — an unknown id throws, so the host dies before serving a route whose guard was never published (fail-closed). Returns the distinct ids it validated, for logging.
SentinelFederationEndpoints
public static class SentinelFederationEndpoints
The inbound-federation endpoint group: “login with Google/Entra/Okta” with Sentinel as the relying party. Mountable and opt-in like the other groups; requires AddSentinelFederation plus an IFederatedIdentityStore in DI.
Methods
static RouteGroupBuilder MapSentinelFederation(this IEndpointRouteBuilder endpoints, string prefix = "/auth/idp", string authPrefix = "/auth")
Maps GET {prefix}/{{idpKey}}/start, GET {prefix}/callback, POST {prefix}/discover.
SentinelImpersonationEndpoints
public static class SentinelImpersonationEndpoints
The impersonation endpoint group. Thin like the admin endpoints: the caller’s snapshot goes to ImpersonationService, which owns the admin-scope fencing, the one-active rule, and both audit ledgers. /consent/approve is the one PUBLIC route — the target proves themselves with the single-purpose mailed token, not with a session.
Methods
static RouteGroupBuilder MapSentinelImpersonation(this IEndpointRouteBuilder endpoints, string prefix = "/sentinel-admin/impersonation")
SentinelPasskeyEndpoints
public static class SentinelPasskeyEndpoints
The passkey/WebAuthn endpoint group: registration ceremonies, passwordless first-factor login, passkey-as-second-factor MFA verification, and credential management. Mountable and opt-in like the other groups; requires AddSentinelPasskeys plus an IPasskeyStore in DI.
Methods
static RouteGroupBuilder MapSentinelPasskeys(this IEndpointRouteBuilder endpoints, string prefix = "/auth/passkey", string authPrefix = "/auth")
Maps POST {prefix}/register/options, {prefix}/register, GET+POST {prefix}/login/options, POST {prefix}/login, {prefix}/mfa/verify, GET {prefix}, DELETE {prefix}/{{credentialId}}.
SentinelPermissionMetadata
public sealed record SentinelPermissionMetadata : IEquatable<SentinelPermissionMetadata>
Endpoint metadata declaring “this route is guarded by SentinelPermissionMetadata.PermissionId”. Declarative, not enforcing: authorization stays with the domain layer / endpoint filters — the metadata exists so route discovery can fail the BOOT when a mounted endpoint names a permission id absent from the definition catalog (fail-closed, Relay spirit).
Constructors
SentinelPermissionMetadata(string PermissionId)
Endpoint metadata declaring “this route is guarded by SentinelPermissionMetadata.PermissionId”. Declarative, not enforcing: authorization stays with the domain layer / endpoint filters — the metadata exists so route discovery can fail the BOOT when a mounted endpoint names a permission id absent from the definition catalog (fail-closed, Relay spirit).
Properties
string PermissionId { get; init; }
SentinelPrivacyEndpoints
public static class SentinelPrivacyEndpoints
The privacy/GDPR endpoint group: Art. 20 export and Art. 17 erasure. Both POST (they act, and the export is heavy), both fenced to sentinel:global:manage inside PersonalDataService — this layer only shapes HTTP.
Methods
static RouteGroupBuilder MapSentinelPrivacy(this IEndpointRouteBuilder endpoints, string prefix = "/sentinel-admin/privacy")
SentinelProfileEndpoints
public static class SentinelProfileEndpoints
The self-service profile endpoint group: identity, device/session management, and the redacted permission snapshot. Every endpoint requires an authenticated Sentinel principal — unauthenticated requests get a 401 problem, never a partial response.
Methods
static RouteGroupBuilder MapSentinelProfile(this IEndpointRouteBuilder endpoints, string prefix = "/profile")
SentinelWebhookAdminEndpoints
public static class SentinelWebhookAdminEndpoints
The webhook administration endpoint group: endpoint CRUD, secret rotation, test deliveries, and the delivery/dead-letter log. Thin like SentinelAdminEndpoints: the caller’s snapshot is resolved here, every decision (including the realm/org fencing) belongs to WebhookAdminService.
Methods
static RouteGroupBuilder MapSentinelWebhookAdmin(this IEndpointRouteBuilder endpoints, string prefix = "/sentinel-admin/webhooks")
SessionView
public sealed record SessionView : IEquatable<SessionView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
SessionView(Guid Id, DateTimeOffset CreatedAt, DateTimeOffset LastSeenAt, string? Device, bool Current)
Properties
DateTimeOffset CreatedAt { get; init; }
DateTimeOffset LastSeenAt { get; init; }
Guid Id { get; init; }
bool Current { get; init; }
string? Device { get; init; }
SetDomainVerifiedRequest
public sealed record SetDomainVerifiedRequest : IEquatable<SetDomainVerifiedRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
SetDomainVerifiedRequest(bool Verified)
Properties
bool Verified { get; init; }
StartImpersonationRequest
public sealed record StartImpersonationRequest : IEquatable<StartImpersonationRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
StartImpersonationRequest(Guid? TargetUserId, string? Reason, Guid? OrganizationId)
Properties
Guid? OrganizationId { get; init; }
Guid? TargetUserId { get; init; }
string? Reason { get; init; }
TokenResponse
public sealed record TokenResponse : IEquatable<TokenResponse>
Success body for /login, /mfa/verify and /refresh. Token properties are omitted (not nulled) in Cookie transport — the whole point of cookie mode is that script never sees tokens.
Constructors
TokenResponse(string Status, string? AccessToken, string? RefreshToken, IReadOnlyList<Guid>? OrganizationIds)
Success body for /login, /mfa/verify and /refresh. Token properties are omitted (not nulled) in Cookie transport — the whole point of cookie mode is that script never sees tokens.
Properties
IReadOnlyList<Guid>? OrganizationIds { get; init; }
string Status { get; init; }
string? AccessToken { get; init; }
string? RefreshToken { get; init; }
UpdateOrganizationRequest
public sealed record UpdateOrganizationRequest : IEquatable<UpdateOrganizationRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
UpdateOrganizationRequest(string? DisplayName)
Properties
string? DisplayName { get; init; }
UpdateRealmRequest
public sealed record UpdateRealmRequest : IEquatable<UpdateRealmRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
UpdateRealmRequest(string? DisplayName)
Properties
string? DisplayName { get; init; }
UpdateRoleRequest
public sealed record UpdateRoleRequest : IEquatable<UpdateRoleRequest>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
UpdateRoleRequest(string? DisplayName)
Properties
string? DisplayName { get; init; }
UpdateWebhookEndpointRequest
public sealed record UpdateWebhookEndpointRequest : IEquatable<UpdateWebhookEndpointRequest>
Patch semantics: omitted (null) members keep their current value; Status is "active" or "disabled".
Constructors
UpdateWebhookEndpointRequest(string? Url, List<string>? EventKinds, string? Status)
Patch semantics: omitted (null) members keep their current value; Status is "active" or "disabled".
Properties
List<string>? EventKinds { get; init; }
string? Status { get; init; }
string? Url { get; init; }
WebhookDeliveryView
public sealed record WebhookDeliveryView : IEquatable<WebhookDeliveryView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
WebhookDeliveryView(Guid Id, Guid EndpointId, string EventKind, string PayloadJson, DateTimeOffset CreatedAt, int AttemptCount, DateTimeOffset NextAttemptAt, DateTimeOffset? DeliveredAt, string? LastError, bool Abandoned)
Properties
DateTimeOffset CreatedAt { get; init; }
DateTimeOffset NextAttemptAt { get; init; }
DateTimeOffset? DeliveredAt { get; init; }
Guid EndpointId { get; init; }
Guid Id { get; init; }
bool Abandoned { get; init; }
int AttemptCount { get; init; }
string EventKind { get; init; }
string PayloadJson { get; init; }
string? LastError { get; init; }
WebhookEndpointCreatedView
public sealed record WebhookEndpointCreatedView : IEquatable<WebhookEndpointCreatedView>
Create response: the endpoint view plus the raw secret, shown this once.
Constructors
WebhookEndpointCreatedView(WebhookEndpointView Endpoint, string Secret)
Create response: the endpoint view plus the raw secret, shown this once.
Properties
WebhookEndpointView Endpoint { get; init; }
string Secret { get; init; }
WebhookEndpointView
public sealed record WebhookEndpointView : IEquatable<WebhookEndpointView>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
WebhookEndpointView(Guid Id, Guid? OrganizationId, string Url, IReadOnlyList<string> EventKinds, string Status, int ConsecutiveFailures, DateTimeOffset CreatedAt, DateTimeOffset? DisabledAt, DateTimeOffset? LastSuccessAt, DateTimeOffset? LastFailureAt)
Properties
DateTimeOffset CreatedAt { get; init; }
DateTimeOffset? DisabledAt { get; init; }
DateTimeOffset? LastFailureAt { get; init; }
DateTimeOffset? LastSuccessAt { get; init; }
Guid Id { get; init; }
Guid? OrganizationId { get; init; }
IReadOnlyList<string> EventKinds { get; init; }
int ConsecutiveFailures { get; init; }
string Status { get; init; }
string Url { get; init; }
WebhookSecretView
public sealed record WebhookSecretView : IEquatable<WebhookSecretView>
Rotate response: the new secret, shown this once.
Constructors
WebhookSecretView(Guid EndpointId, string Secret)
Rotate response: the new secret, shown this once.
Properties
Guid EndpointId { get; init; }
string Secret { get; init; }
Nuvora.Nexus.Sentinel.AspNetCore.HealthChecks
SentinelBreakGlassHealthCheck
public sealed class SentinelBreakGlassHealthCheck : IHealthCheck
The break-glass drill health check: DEGRADED when the realm’s break-glass access has not been exercised (drilled) within BreakGlassPolicy.DrillIntervalDays — an emergency door nobody has opened in months must be assumed rusted shut. Healthy otherwise; never Unhealthy (a stale drill is an operational smell, not an outage).
Constructors
SentinelBreakGlassHealthCheck(BreakGlassService breakGlass, IOptions<SentinelAspNetOptions> options)
The break-glass drill health check: DEGRADED when the realm’s break-glass access has not been exercised (drilled) within BreakGlassPolicy.DrillIntervalDays — an emergency door nobody has opened in months must be assumed rusted shut. Healthy otherwise; never Unhealthy (a stale drill is an operational smell, not an outage).
Methods
Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
Runs the health check, returning the status of the component being checked.
SentinelBreakGlassHealthCheckExtensions
public static class SentinelBreakGlassHealthCheckExtensions
Methods
static IHealthChecksBuilder AddSentinelBreakGlassHealthCheck(this IHealthChecksBuilder builder, string name = "sentinel_break_glass")
Registers the break-glass drill health check. Requires AddSentinelBreakGlass() (the check resolves BreakGlassService); the realm checked is SentinelAspNetOptions.DefaultRealmId.
Nuvora.Nexus.Sentinel.AspNetCore.Passkeys
PasskeyAssertionResult
public sealed record PasskeyAssertionResult : IEquatable<PasskeyAssertionResult>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
PasskeyAssertionResult(PasskeyAssertionStatus Status, PasskeyCredential? Credential = null, bool UserVerified = false)
Properties
PasskeyAssertionStatus Status { get; init; }
PasskeyCredential? Credential { get; init; }
bool UserVerified { get; init; }
PasskeyAssertionStatus
public enum PasskeyAssertionStatus
Outcome of a verified (or rejected) passkey assertion ceremony.
Values
SuccessSignCountRegression— The signature counter went backwards: the strongest available signal that the credential was cloned. The assertion is rejected and callers emitpasskey.signcount_regression.Failed— Unknown ceremony, expired challenge, unknown credential, or failed cryptographic verification — one bucket on purpose (anti-enumeration posture).
PasskeyService
public sealed class PasskeyService
WebAuthn ceremony orchestration over Fido2NetLib. This is the only place in the codebase that touches the FIDO2 protocol — Core holds just the credential entity and the store port.
Challenge round-trip: each ceremony gets a random ceremony id; the SHA-256 of the issued challenge is stored in IChallengeStore under that id (ttl SentinelPasskeyOptions.CeremonyLifetime, single attempt). At completion the challenge is read back out of the client’s clientDataJSON and hash-verified against the store — success proves this exact challenge was server-issued, unexpired, and unused (single-use consumption is the store’s contract), after which the original options are reconstructed deterministically from configuration for Fido2NetLib’s verification. No server-side options blob needs to survive the round-trip, so the existing challenge port works fleet-wide unchanged.
Constructors
PasskeyService(IOptions<SentinelPasskeyOptions> options, IChallengeStore challenges, IPasskeyStore passkeys, ISentinelClock clock)
Methods
ValueTask<(string CeremonyId, AssertionOptions Options)> BeginAssertionAsync(CancellationToken ct = default(CancellationToken))
Starts an assertion ceremony. Usernameless by design (passkeys-first): no allowCredentials, so the browser offers whatever discoverable credentials it holds for the RP and the server learns the user from the verified assertion — the options leak nothing about who exists. The same ceremony feeds both passwordless login and the MFA step-up path.
ValueTask<(string CeremonyId, CredentialCreateOptions Options)> BeginRegistrationAsync(User user, CancellationToken ct = default(CancellationToken))
Starts a registration ceremony for an authenticated user. Existing credentials are excluded so an authenticator can’t double-enroll; resident key is preferred and user verification is preferred — the ceremony records what the authenticator actually did, and first-factor eligibility is decided from that record, not demanded up front (demanding UV would lock out second-factor-only security keys).
ValueTask<PasskeyAssertionResult> CompleteAssertionAsync(string ceremonyId, AuthenticatorAssertionRawResponse response, CancellationToken ct = default(CancellationToken))
Verifies an assertion: challenge round-trip, credential lookup, signature verification, sign-count advance. On success the stored counter and last-used stamp are updated.
ValueTask<PasskeyCredential?> CompleteRegistrationAsync(string ceremonyId, User user, AuthenticatorAttestationRawResponse response, string? label, CancellationToken ct = default(CancellationToken))
Verifies an attestation response and stores the credential. Attestation conveyance is none (the default posture: we authenticate users, not authenticator supply chains), so the AAGUID is informational. Returns null on any verification failure.
SentinelPasskeyOptions
public sealed class SentinelPasskeyOptions
WebAuthn relying-party configuration. Kept as its own small POCO — this is protocol identity (what the browser scopes credentials to), not HTTP plumbing, so it does not fold into SentinelAspNetOptions.
Properties
ISet<string> Origins { get; set; }
Web origins allowed to perform ceremonies (e.g. https://app.example.com). Assertions from any other origin fail verification — this is the phishing-resistance anchor of the whole passkey design, never leave it empty in production.
TimeSpan CeremonyLifetime { get; set; }
How long an issued challenge stays redeemable. Short by design: a ceremony is an interactive browser round-trip, not a durable token.
string RpId { get; set; }
The relying-party id — the registrable domain credentials are scoped to (e.g. example.com). Changing it orphans every previously registered credential, so treat it as immutable once users have enrolled.
string RpName { get; set; }
Human-readable relying-party name shown in authenticator prompts.
Nuvora.Nexus.Sentinel.AspNetCore.Privacy
SentinelRetentionService
public sealed class SentinelRetentionService : BackgroundService
Hosted retention sweep: runs RetentionService.RunOnceAsync on SentinelRetentionOptions.SweepInterval (daily by default), each pass in its own DI scope (the retention store is DbContext-bound in persistent setups). A failing sweep logs and waits for the next tick — retention is idempotent, so missed work is simply picked up later.
Constructors
SentinelRetentionService(IServiceScopeFactory scopeFactory, SentinelRetentionOptions options, ILogger<SentinelRetentionService> logger)
Hosted retention sweep: runs RetentionService.RunOnceAsync on SentinelRetentionOptions.SweepInterval (daily by default), each pass in its own DI scope (the retention store is DbContext-bound in persistent setups). A failing sweep logs and waits for the next tick — retention is idempotent, so missed work is simply picked up later.
Methods
override Task ExecuteAsync(CancellationToken stoppingToken)
This method is called when the IHostedService starts. The implementation should return a task that represents the lifetime of the long running operation(s) being performed.
SentinelRetentionServiceCollectionExtensions
public static class SentinelRetentionServiceCollectionExtensions
Methods
static IServiceCollection AddSentinelRetentionService(this IServiceCollection services)
Registers the daily retention sweep. Requires AddSentinelPrivacy().
Nuvora.Nexus.Sentinel.AspNetCore.Webhooks
SentinelWebhookDispatcherServiceCollectionExtensions
public static class SentinelWebhookDispatcherServiceCollectionExtensions
Registration for the webhook delivery side in ASP.NET Core hosts: the IHttpClientFactory-backed HTTP transport for WebhookDispatcher and the polling hosted service. Call ALONGSIDE the meta package’s AddSentinelWebhooks(), which registers the store, the enqueue sink composition, and the dispatcher itself.
Methods
static IServiceCollection AddSentinelWebhookDispatcher(this IServiceCollection services)
Registers the HTTP transport (TryAdd — a host’s or a test’s own Func<WebhookRequest, CancellationToken, Task<int>> registered earlier wins) and WebhookDispatcherService. Idempotent.
Fields
const string HttpClientName = "sentinel-webhooks"
Named client so hosts can attach their own handlers/policies (proxies, extra telemetry).
WebhookDispatcherService
public sealed class WebhookDispatcherService : BackgroundService
The delivery poll loop: every WebhookDispatcherOptions.PollInterval, opens a service scope (the store may be DbContext-bound), resolves WebhookDispatcher, and runs one claim-and-deliver pass. Multiple nodes can run this concurrently — the claim lease (IWebhookStore.ClaimDueAsync) prevents double-sends. Failures are logged and the loop continues; delivery machinery must never take the host down.
Constructors
WebhookDispatcherService(IServiceScopeFactory scopeFactory, WebhookDispatcherOptions options, ILogger<WebhookDispatcherService> logger)
The delivery poll loop: every WebhookDispatcherOptions.PollInterval, opens a service scope (the store may be DbContext-bound), resolves WebhookDispatcher, and runs one claim-and-deliver pass. Multiple nodes can run this concurrently — the claim lease (IWebhookStore.ClaimDueAsync) prevents double-sends. Failures are logged and the loop continues; delivery machinery must never take the host down.
Methods
override Task ExecuteAsync(CancellationToken stoppingToken)
This method is called when the IHostedService starts. The implementation should return a task that represents the lifetime of the long running operation(s) being performed.