elsa-core/specs/012-external-authentication/data-model.md
2026-07-24 19:04:26 +02:00

12 KiB

Data Model: External Authentication

Conventions

  • IDs are opaque strings generated by Elsa and never reused.
  • TenantId = "*" means host-wide/tenant-agnostic; TenantId = "" means only Elsa's default tenant.
  • Timestamps are UTC DateTimeOffset.
  • Revisions are monotonically increasing 64-bit integers.
  • Secret values, provider tokens, completion codes, refresh tokens, raw subjects, and unrestricted claims are never stored in public connection documents.
  • JSON fields are opaque, versioned extension settings. Their provider owns validation and migration.

IdentityProviderConnection

Represents one database-owned provider trust relationship. Configuration-owned connections use the same domain model but are materialized from options and never written through the store.

Field Type Rules
Id string Immutable Connection ID
TenantId string *, empty default tenant, or concrete tenant
Key string Stable URL/presentation key; normalized; unique with TenantId among database rows
AdapterType string Must identify an installed, deployment-allowed adapter
AdapterSettingsVersion int Positive schema version
AdapterSettings JSON object Opaque to registry; adapter validates/migrates
SecretBindings map<string, SecretBinding> Names declared by descriptor; contains no values
DisplayName string Required, bounded, safe plain text
IconId string? Trusted server asset identifier only
DisplayOrder int Deterministic tie-break by normalized key
IsDefault bool At most one effective automatic default per scope
IsEnabled bool Administrative intent; requires validity to be effective
ArchivedAt DateTimeOffset? Archive is logical deletion
UnlinkedPolicy PolicySelection? Null means deployment default
PermissionGrantSources list Ordered and descriptor-validated
ClaimProjection ClaimProjection Allowlist, value limits, and redaction policy
UpstreamLogoutMode enum Disabled, UserChoice, or Always
Revision long Changes on every mutation; concurrency token
MaterialRevision string Non-secret fingerprint of all sign-in-affecting state
CreatedAt / UpdatedAt DateTimeOffset Audit metadata

Constraints

  • Database unique index: (TenantId, Key).
  • Creation/update additionally rejects an existing configuration-owned (TenantId, Key).
  • A tenant key may not collide with an inherited host-wide key in its effective registry.
  • Id survives archive/restore. Restore returns disabled and requires revalidation.
  • Display-only changes advance Revision but may retain MaterialRevision.
  • Adapter/trust settings, scope, Secret Binding generation, policy, claim projection, grants, or enable/archive state affect MaterialRevision.

State Transitions

Draft/Disabled --validate + enable--> Enabled
Enabled --disable------------------> Disabled
Draft/Disabled/Enabled --archive---> Archived
Archived --restore-----------------> Disabled

Invalid or unresolved configuration never becomes effectively enabled. Test observations do not change lifecycle state.

SecretBinding

Field Type Rules
ResolverType string Installed, deployment-allowed resolver
Reference string Non-secret lookup key
ExpectedType string? Optional resolver/type constraint
ExpectedScope string? Optional resolver/scope constraint

Resolution returns a transient value and opaque nonreversible generation fingerprint. The fingerprint contributes to material revision but is not exposed or stored in API models.

PolicySelection

Field Type Rules
Type string Installed, deployment-allowed Unlinked Identity Policy
SettingsVersion int Positive schema version
Settings JSON object Provider-owned validation/migration

Built-in types are Reject and CreateUser.

GrantSourceSelection

Field Type Rules
Type string Installed, deployment-allowed Permission Grant Source
SettingsVersion int Positive schema version
Settings JSON object Provider-owned validation/migration
Order int Stable evaluation order

V1 types are Elsa role grants, claim mappings, and group mappings. Stored permission strings remain open vocabulary, but actor delegation and deployment boundaries are validated before save.

ClaimProjection

Field Type Rules
AllowedClaimTypes set Only these normalized claims survive sign-in processing
RedactedClaimTypes set Values hidden in preview/diagnostics
MaximumClaimCount int Secure bounded default; deployment may lower
MaximumValueLength int Per scalar/array member
MaximumTotalBytes int Entire normalized projection

Values are only strings or string arrays. Every value carries adapter/provider provenance during evaluation. Claims outside the projection are discarded.

Associates one provider identity with one tenant-owned Elsa User.

Field Type Rules
Id string Immutable
TenantId string Resolved target tenant; never * for a user link
ConnectionId string Immutable Identity Provider Connection ID
Issuer string Validated canonical issuer namespace
SubjectHash string Keyed hash of canonical provider subject
SubjectHint string? Optional masked operator hint; never the raw subject
UserId string Elsa User in the same tenant
CreatedAt DateTimeOffset Creation/prelink time
LastSignedInAt DateTimeOffset? Safe operational metadata

Constraints

  • Unique index: (TenantId, ConnectionId, Issuer, SubjectHash).
  • Foreign key to User; broker additionally enforces tenant equality.
  • Connection archive preserves links.
  • Explicit unlink removes the active association and emits a notification.
  • Concurrent JIT and prelink use one atomic create-link-or-get-existing operation.

User Migration

The existing User entity changes:

Field Change
HashedPassword Nullable; both password fields are present or absent together
HashedPasswordSalt Nullable

Credential-less users cannot authenticate through legacy or broker-local password validation. Existing password-backed rows require no data change.

JIT provisioning generates and atomically reserves a globally unique internal User.Name, sets the resolved tenant, leaves password fields null, and creates the External Identity Link in the same transaction.

AuthenticationClient

Deployment-configured registration for an Elsa client.

Field Type Rules
ClientId string Unique immutable identifier
DisplayName string Operator-facing
ClientType enum Confidential or Public
CallbackUris set Exact HTTPS matches; development loopback may be explicitly allowed
LogoutCallbackUris set Exact matches
AllowedOrigins set Required for public clients; no wildcard
AllowedReturnPathPrefixes set Segment-boundary prefixes for post-authentication client-local navigation
SecretBinding SecretBinding? Required for confidential clients; forbidden for public clients
IsEnabled bool Disabled clients cannot initiate or exchange

Authentication Clients are not Elsa API Applications and contain no roles or permissions.

BrokerTransaction

Shared, protected, short-lived provider/local/preview correlation state.

Field Type Rules
HandleHash string Keyed hash of random browser-visible state handle
Purpose enum ExternalSignIn, LocalSignIn, Preview, UpstreamLogout
ClientId string Registered Authentication Client or preview purpose
CallbackUri URI Exact registered callback
ReturnPath string Validated client-local path
TenantId string Resolved before redirect
ConnectionId string? Required for external/preview
ConnectionMaterialRevision string? Captured effective revision
SecretGenerationFingerprint string? Protected, nonreversible
PkceChallenge string S256 only
ProviderNonce string? External/preview
ProtectedPayload bytes Data-protected adapter state
ExpiresAt DateTimeOffset Default 10 minutes
ConsumedAt DateTimeOffset? Atomic single-use marker

The public handle contains no protected payload. Atomic take transitions pending to consumed; expired or mismatched state is never revived.

AuthorizationGrant

Single-use Elsa completion code record.

Field Type Rules
CodeHash string Keyed hash of random code
ClientId string Bound client
CallbackUri URI Bound exact callback
TenantId string Bound tenant
UserId string Resolved Elsa User
ExternalSessionId string? Null for broker-local sign-in
PkceChallenge string S256
ExpiresAt DateTimeOffset Default 60 seconds
ConsumedAt DateTimeOffset? Atomic single use

ExternalAuthenticationSession

Field Type Rules
Id string Included as safe session claim in access tokens
TenantId string Resolved target tenant
UserId string Same-tenant Elsa User
ConnectionId string Source connection
ConnectionMaterialRevision string Revision at full sign-in
Issuer string Validated issuer
SubjectHash string No raw subject
ExternalGrants JSON array Permission strings plus source provenance; no raw claims
StartedAt DateTimeOffset Full external sign-in
LastRefreshedAt DateTimeOffset Rotation time
ExpiresAt DateTimeOffset Maximum session age; default eight hours
RefreshExpiresAt DateTimeOffset Inactivity bound
CurrentRefreshTokenHash string Keyed hash of current opaque token
RefreshGeneration long Compare-and-swap rotation counter
RevokedAt DateTimeOffset? Explicit or reuse-detection revocation
RevocationReason string? Safe category

Refresh atomically verifies current token hash and generation, rotates the token, reevaluates current Elsa-owned role grants, and retains ExternalGrants. Reuse of a superseded token revokes the session.

ConnectionObservation

Latest on-demand test result only.

Field Type Rules
ConnectionId string Primary key
TestedMaterialRevision string Determines freshness
ObservedAt DateTimeOffset UTC
Status enum Succeeded, Failed, Warning
Category string Stable redacted category
Duration TimeSpan Test duration
Summary string Safe bounded message
Warnings list Safe bounded warnings
CorrelationId string Diagnostic correlation

An observation is stale when its tested revision differs from the current effective material revision. No history table is required.

PreviewResult

Field Type Rules
HandleHash string One-time result handle
AdministratorId string Initiating authenticated actor
TenantId string Preview target
ConnectionId string Draft connection
MaterialRevision string Exact previewed revision
Issuer string Validated issuer
MaskedSubject string Never raw subject
ProjectedClaims JSON object Allowlisted and descriptor-redacted only
PolicyDecision JSON object Proposed action; no mutation
PermissionProjection JSON array Proposed grants and provenance
Warnings list Safe bounded warnings
ExpiresAt DateTimeOffset Default 10 minutes
ConsumedAt DateTimeOffset? One-time read

PermissionDescriptor

Runtime metadata only; not persisted by this feature.

Field Type Rules
Name string Elsa permission string
DisplayName string Optional authoring label
Description string? Optional
Category string? Optional grouping
SourceModule string Provenance

Descriptors may be incomplete. Their absence never invalidates a permission string.