API reference — Protocols
Nuvora.Nexus.Sentinel.Scim
SCIM 2.0 provisioning server for Sentinel: per-organization bearer-token auth, Users AND Groups (fixes the Node version's users-only gap), the standard filter subset, and RFC 7644 PATCH — mounted with MapSentinelScim().
dotnet add package Nuvora.Nexus.Sentinel.Scim
Nuvora.Nexus.Sentinel.Scim
ScimConstants
public static class ScimConstants
Schema URNs and media type of the SCIM 2.0 wire format (RFC 7643, RFC 7644).
Fields
const string ErrorSchema = "urn:ietf:params:scim:api:messages:2.0:Error"
const string GroupSchema = "urn:ietf:params:scim:schemas:core:2.0:Group"
const string ListResponseSchema = "urn:ietf:params:scim:api:messages:2.0:ListResponse"
const string MediaType = "application/scim+json"
RFC 7644 §3.1 media type; responses carry it, and requests may send it or plain application/json.
const string PatchOpSchema = "urn:ietf:params:scim:api:messages:2.0:PatchOp"
const string ResourceTypeSchema = "urn:ietf:params:scim:schemas:core:2.0:ResourceType"
const string SchemaSchema = "urn:ietf:params:scim:schemas:core:2.0:Schema"
const string ServiceProviderConfigSchema = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"
const string UserSchema = "urn:ietf:params:scim:schemas:core:2.0:User"
ScimEmail
public sealed record ScimEmail : IEquatable<ScimEmail>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimEmail(string Value, bool Primary, string? Type = null)
Properties
bool Primary { get; init; }
string Value { get; init; }
string? Type { get; init; }
ScimEmailRequest
public sealed class ScimEmailRequest
Properties
bool? Primary { get; set; }
string? Type { get; set; }
string? Value { get; set; }
ScimErrorBody
public sealed record ScimErrorBody : IEquatable<ScimErrorBody>
RFC 7644 §3.12 error shape. ScimErrorBody.Status is the HTTP status as a STRING, per the RFC.
Constructors
ScimErrorBody(IReadOnlyList<string> Schemas, string Status, string? ScimType, string? Detail)
RFC 7644 §3.12 error shape. ScimErrorBody.Status is the HTTP status as a STRING, per the RFC.
Properties
IReadOnlyList<string> Schemas { get; init; }
string Status { get; init; }
string? Detail { get; init; }
string? ScimType { get; init; }
ScimGroupRequest
public sealed class ScimGroupRequest
Properties
List<ScimMemberRequest>? Members { get; set; }
string? DisplayName { get; set; }
string? ExternalId { get; set; }
ScimGroupResource
public sealed record ScimGroupResource : IEquatable<ScimGroupResource>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimGroupResource(IReadOnlyList<string> Schemas, string Id, string DisplayName, IReadOnlyList<ScimMemberRef> Members, ScimMeta Meta)
Properties
IReadOnlyList<ScimMemberRef> Members { get; init; }
IReadOnlyList<string> Schemas { get; init; }
ScimMeta Meta { get; init; }
string DisplayName { get; init; }
string Id { get; init; }
ScimListResponse
public sealed record ScimListResponse : IEquatable<ScimListResponse>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimListResponse(IReadOnlyList<string> Schemas, int TotalResults, int StartIndex, int ItemsPerPage, IReadOnlyList<object> Resources)
Properties
IReadOnlyList<object> Resources { get; init; }
IReadOnlyList<string> Schemas { get; init; }
int ItemsPerPage { get; init; }
int StartIndex { get; init; }
int TotalResults { get; init; }
Methods
static ScimListResponse Of(IReadOnlyList<object> resources, int totalResults, int startIndex)
ScimMemberRef
public sealed record ScimMemberRef : IEquatable<ScimMemberRef>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimMemberRef(string Value, string? Display = null)
Properties
string Value { get; init; }
string? Display { get; init; }
ScimMemberRequest
public sealed class ScimMemberRequest
Properties
string? Display { get; set; }
string? Value { get; set; }
ScimMeta
public sealed record ScimMeta : IEquatable<ScimMeta>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimMeta(string ResourceType, DateTimeOffset Created, DateTimeOffset LastModified, string Location)
Properties
DateTimeOffset Created { get; init; }
DateTimeOffset LastModified { get; init; }
string Location { get; init; }
string ResourceType { get; init; }
ScimName
public sealed record ScimName : IEquatable<ScimName>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimName(string? Formatted, string? GivenName, string? FamilyName)
Properties
string? FamilyName { get; init; }
string? Formatted { get; init; }
string? GivenName { get; init; }
ScimNameRequest
public sealed class ScimNameRequest
Properties
string? FamilyName { get; set; }
string? Formatted { get; set; }
string? GivenName { get; set; }
ScimPatchOperation
public sealed class ScimPatchOperation
Properties
JsonElement Value { get; set; }
Raw JSON: SCIM patch values are polymorphic (bool, string, object, array — and Azure AD sends booleans as “True”/“False” strings).
string? Op { get; set; }
string? Path { get; set; }
ScimPatchRequest
public sealed class ScimPatchRequest
Properties
List<ScimPatchOperation>? Operations { get; set; }
List<string>? Schemas { get; set; }
ScimServerOptions
public sealed class ScimServerOptions
Options for the SCIM 2.0 server surface.
Properties
int MaxPageSize { get; set; }
Hard cap on page size (RFC 7644 §3.4.2.4 and the ServiceProviderConfig filter.maxResults): a request’s count is clamped to this, and it is also the default page size when count is omitted.
string BaseUrl { get; set; }
Path prefix the SCIM endpoint group mounts under. The conventional SCIM base path; combined with the host’s PathBase at request time when building meta.location.
ScimTokenCreated
public sealed record ScimTokenCreated : IEquatable<ScimTokenCreated>
Creation result: ScimTokenCreated.Secret is the full sct_ token, returned ONCE — only its hash is stored (same posture as snt_ API keys).
Constructors
ScimTokenCreated(ScimToken Token, string Secret)
Creation result: ScimTokenCreated.Secret is the full sct_ token, returned ONCE — only its hash is stored (same posture as snt_ API keys).
Properties
ScimToken Token { get; init; }
string Secret { get; init; }
ScimTokenService
public sealed class ScimTokenService
SCIM token lifecycle + authentication. Admin endpoint wiring for mint/revoke arrives with the admin UI wave; until then hosts call this service directly.
Constructors
ScimTokenService(IScimStore store, ISentinelClock clock)
SCIM token lifecycle + authentication. Admin endpoint wiring for mint/revoke arrives with the admin UI wave; until then hosts call this service directly.
Methods
ValueTask RevokeAsync(Guid tokenId, CancellationToken cancellationToken = default(CancellationToken))
ValueTask<ScimToken?> AuthenticateAsync(string secret, CancellationToken cancellationToken = default(CancellationToken))
Null for malformed, unknown, revoked and expired tokens alike — a probing caller learns nothing (anti-enumeration).
ValueTask<ScimTokenCreated> CreateAsync(Guid realmId, Guid organizationId, string label, DateTimeOffset? expiresAt = null, CancellationToken cancellationToken = default(CancellationToken))
Mints a SCIM bearer token for one organization. The returned secret (sct_ + 43 base64url chars = 256 bits of entropy) is shown exactly once; only its SHA-256 lands in the store.
Fields
const string TokenPrefix = "sct_"
SCIM-token prefix: greppable in leaked logs, fingerprintable by secret scanners — same rationale as snt_ API keys.
ScimUserRequest
public sealed class ScimUserRequest
Properties
List<ScimEmailRequest>? Emails { get; set; }
ScimNameRequest? Name { get; set; }
bool? Active { get; set; }
Nullable so “absent” (default true on create) is distinguishable from an explicit false.
string? DisplayName { get; set; }
string? ExternalId { get; set; }
string? UserName { get; set; }
ScimUserResource
public sealed record ScimUserResource : IEquatable<ScimUserResource>
Defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
Constructors
ScimUserResource(IReadOnlyList<string> Schemas, string Id, string? ExternalId, string UserName, ScimName? Name, string? DisplayName, bool Active, IReadOnlyList<ScimEmail> Emails, ScimMeta Meta)
Properties
IReadOnlyList<ScimEmail> Emails { get; init; }
IReadOnlyList<string> Schemas { get; init; }
ScimMeta Meta { get; init; }
ScimName? Name { get; init; }
bool Active { get; init; }
string Id { get; init; }
string UserName { get; init; }
string? DisplayName { get; init; }
string? ExternalId { get; init; }
SentinelScimEndpoints
public static class SentinelScimEndpoints
The SCIM 2.0 endpoint group: /ServiceProviderConfig, /Schemas, /ResourceTypes, and full Users AND Groups resources (fixing the Node version’s users-only gap) behind per-org sct_ bearer auth.
The RFC subset is deliberate and honest: single-clause eq filters on userName/externalId (Users) and displayName (Groups); PATCH replace on user active/name/emails/displayName/userName/externalId; PATCH add/remove/replace on group members and displayName. Everything else in RFC 7644 answers 501 in the §3.12 error shape — never a silently wrong 200. Bulk, sorting, ETags and attribute projection are not implemented and say so in ServiceProviderConfig.
SCIM DELETE of a user deactivates (soft, UserStatus.Deactivated): user rows anchor audit chains and security events, so provisioning-driven deletes must never destroy them — PII erasure is the crypto-shredding flow, not SCIM’s. Group DELETE is hard: groups are aggregation edges, not audit anchors.
Methods
static RouteGroupBuilder MapSentinelScim(this IEndpointRouteBuilder endpoints, ScimServerOptions? options = null)
Nuvora.Nexus.Sentinel.Scim.DependencyInjection
ScimServiceCollectionExtensions
public static class ScimServiceCollectionExtensions
Registration for the SCIM server, Relay DI style: TryAdd idempotency, working in-memory default for the store port.
Methods
static IServiceCollection AddSentinelScim(this IServiceCollection services, Action<ScimServerOptions>? configure = null)
Registers ScimServerOptions, ScimTokenService and — unless the host registered one (e.g. the EF adapter’s EfScimStore) — the in-memory IScimStore. Pair with MapSentinelScim() on the endpoint builder.