StellaOps Authority
Authority is the StellaOps OIDC/OAuth2 control plane. It mints the short-lived (default access-token lifetime: 2 minutes), optionally sender-constrained operational tokens (OpToks) that every StellaOps service, CLI, and UI uses to authenticate to one another.
Audience: platform operators configuring identity providers and tenancy, and service/integration authors who need to understand the token, scope, and admin surfaces Authority exposes.
Recent changes
- 2026-07-19 - Built-in Console role assignment consistency. User updates accept roles advertised by the compiled
GetDefaultRoles()catalog even when an installation has no duplicate tenant-local role-table row. Tenant-created roles still require persisted role records. This keeps the Users editor, role list, metadata persistence, and authorization-code scope catalog aligned. - 2026-07-19 - Console admin fresh-auth enforcement. Tenant-scoped Console admin mutations now enforce the existing
RequireFreshAuth()contract:auth_timemust be no more than five minutes old, with one minute of allowed future clock skew. Missing, invalid, stale, or excessively future claims fail with401 fresh_auth_required; read-only admin routes remain available without step-up so operators can inspect state before reauthenticating to mutate it. - 2026-07-18 - Global identity-provider admin API. Global administrators can list, create, update, delete, enable, disable, apply, status-check, and preflight LDAP/OIDC/SAML configuration under
/console/admin/identity-providers. The surface is process-global (no tenant header), requiresui.adminplusauthority:idp.read|write, requires fresh authentication for mutations, rejects inline secret material, and reports typed mounted/admitted/loaded/healthy status. Candidate connection tests run through the mounted signed provider bundle without persistence. - 2026-07-15 - Front-door-safe login hero. The embedded interactive-login hero is also served anonymously at
/connect/assets/img/stella-identity.png, so the gateway-routed authorization page receives Authority’s placement-specific sunrise image instead of the Console’s legacy/assetsidentity artwork. - 2026-06-13 - LDAP native runtime package hook. Authority image build paths now pass an Authority-only
EXTRA_RUNTIME_PACKAGESbuild argument for the Linux OpenLDAP client runtime package (AUTHORITY_LDAP_NATIVE_PACKAGE, defaultlibldap-2.5-0). This keeps OIDC/SAML/LDAP provider assemblies in signed mounted bundles while ensuring an Authority image rebuilt from the offline package source can initializeSystem.DirectoryServices.Protocols. Local IdP runtime proof still requires the rebuilt/imported Authority image plus local fixture images forquay.io/keycloak/keycloak:24.0andosixia/openldap:1.5.0. - 2026-06-12 - Standard plugin crypto publish boundary. The standard local identity-provider plugin registers host-owned default crypto services directly and no longer references
StellaOps.Cryptography.DependencyInjection. The shared crypto DI package itself also compiles optional regional/simulator provider registrations only behindStellaOpsEnableOptionalCryptoProviders=true, so the base Authority publish graph is not allowed to inherit GOST/SM/PQ/simulator/CSP provider payloads through standard local auth. - 2026-06-11 - Provider admission and future MFA registry guard. Authority provider admission now rejects any enabled descriptor whose declared assembly identity does not match the cataloged provider type, before registrar activation. The operator registry keeps TOTP/WebAuthn/Email/SMS MFA entries disabled because those provider boundaries are cataloged as future work; MFA can still be satisfied by a loaded identity-provider plugin that reports the
mfacapability. - 2026-06-05 - Auth.ServerIntegration crypto boundary. The resource-server integration library no longer references the shared
StellaOps.Configurationpackage. It bindsStellaOpsResourceServerOptionsdirectly fromMicrosoft.Extensions.Configuration, so downstream services such as SmRemote do not pull the shared crypto DI package or optional regional/simulator crypto provider projects through Authority validation helpers. - 2026-07-23 - One Authority config root. Base, recommended, harness, and IdP-testing compose surfaces now share
/app/etc/authority/plugins, backed bydevops/etc/authority/plugins/. Plugin overlays may change the executable scan root to/app/plugins/authority, but they do not redirect the configuration directory. Standard bootstrap and LDAP/OIDC/SAML/harness/ registry config therefore converge from one tracked source. Signed bundle production and runtime probe proof remain open inSPRINT_20260604_008_Authority_composable_idp_mfa_crypto_providers.md. - 2026-06-03 -
/connect/authorizeroute ownership. Authority now maps the interactive authorization-code+PKCE login handler at both/authorizeand/connect/authorize. This matches the discovery/OpenIddict endpoint configuration and the compose Platform environment settings consumed by the Console. - 2026-04-30 — Tenant compliance profiles. Authority tenant views and console-admin tenant summaries expose a nullable
complianceProfilefor DORA, NIS2, and CRA filtering. Console admin create/update validates LEIs offline using the ISO 17442 checksum and stores the normalized profile in tenant metadata. Runtime consumers read the source-owned nullable profile viaGET /api/v1/tenants/{tenantId}/compliance-profilewithout receiving operator settings, deployment posture, or secret refs. Seetenant-model.mdandtenant-compliance-profile-v1.md. - 2026-04-29 — VEX SSE fails closed. Authority Console no longer presents
/console/vex/eventsas live VEX SSE. Until a durable tenant-scoped VEX event source exists, the endpoint fails closed with501 vex_events_stream_unsupported, recordsauthority.console.vex.events, and callers must poll/console/vex/statements. - 2026-04-24 — No silent in-memory/null defaults. Production-like Authority composition no longer binds remaining in-memory/null runtime defaults: timestamping stores fail closed without explicit local/test opt-in; Auth client token cache resolution requires a file/messaging cache outside Development/Testing (or when no host environment is registered);
NullAuthoritySessionAccessoris guarded by environment orAuthority:Storage:AllowNullSessionAccessor=true; direct IssuerDirectory in-memory registration requires an explicit local/test gate; and production Authority/Postgres adapters depend on the neutralStellaOps.Authority.Persistence.Storescontracts rather than the local in-memory store namespace. - 2026-04-16 — Durable DPoP state. Authority no longer uses live in-memory DPoP replay or nonce state outside
Testing; non-testing DPoP-enabled runtime now requires durable Valkey-backed state, with restart-survival proof inAuthorityDpopRuntimeTests. The AU1–AU10 and RR1–RR10 gap-remediation package landed undergaps/with deliverable map and evidence layout.
Responsibilities
- Expose authorization-code+PKCE, client-credentials, password, and refresh-token flows with optional DPoP or mTLS sender-constraint binding. (Device-code is configured for lifetime only via
SetDeviceCodeLifetime;AllowDeviceCodeFlowis not enabled, so device-code is not yet an active grant — seeProgram.cs.) - Manage signing keys and JWKS rotation. (PoE/entitlement enforcement is owned by Signer, not Authority.)
- Emit structured audit events (via
StellaOps.Audit.Emissionto the Timeline unified audit store) and enforce tenant-aware scope policies. - Provide a plugin surface for custom identity providers and credential validators (standard, LDAP, OIDC, SAML).
Source of truth: token issuance filters requested scopes against
authority.clients.allowed_scopes(seeAuthorizeEndpoint.cs/principal.SetScopes(...)). Theauthority.permissionstable is the RBAC catalog consumed by the Console Admin role editor and is not consulted at JWT issuance time. SeeStellaOps.Auth.Abstractions/StellaOpsScopes.csand architecture.md §4.3.
Key components
StellaOps.Authorityweb host (OpenIddict server —AddOpenIddict().AddServer(...)inProgram.cs).- Identity-provider plugins, each shipping a registrar +
IIdentityProviderPlugin:StellaOps.Authority.Plugin.Standard(PluginType => "standard") — first-party local credential store.StellaOps.Authority.Plugin.Ldap(PluginType => "ldap").StellaOps.Authority.Plugin.Oidc(OidcIdentityProviderPlugin).StellaOps.Authority.Plugin.Saml(SamlIdentityProviderPlugin).
StellaOps.Auth.Abstractions— canonical scope catalog (StellaOpsScopes) and telemetry metadata (AuthorityTelemetry).StellaOps.Auth.ServerIntegration- resource-server validation (AddStellaOpsResourceServerAuthentication) used by Authority’s own admin endpoints and by downstream services. This library intentionally does not depend onStellaOps.Configurationor crypto provider DI; downstream resource servers must not receive optional regional/simulator crypto provider payloads merely by enabling Authority JWT validation.StellaOps.Authority.Persistence— PostgreSQL stores + embeddedMigrations/**/*.sql(auto-migrated on startup).StellaOps.IssuerDirectory.*— issuer directory core/infrastructure/web service (separate host).- Telemetry and audit pipeline feeding Security/Observability stacks.
HTTP surface (verified against source)
OAuth/OIDC endpoints (registered on the OpenIddict server in Program.cs):
| Path | Method(s) | Purpose |
|---|---|---|
/token | POST | Token endpoint (password, client-credentials, authorization-code, refresh grants). |
/authorize | GET/POST | Authorization-code + PKCE endpoint (PKCE required: RequireProofKeyForCodeExchange). |
/connect/authorize | GET/POST | Conventional OIDC authorization endpoint alias; handled by the same login handler as /authorize. |
/connect/assets/img/stella-identity.png | GET | Anonymous gateway-safe alias for the embedded interactive-login hero. |
/introspect | POST | Token introspection. |
/revoke | POST | Token revocation. |
/jwks | GET | JWKS — served by the custom AuthorityJwksService handler (OpenIddict passthrough). |
/.well-known/openid-configuration | GET | OIDC discovery (ConfigureAuthorityDiscoveryHandler). |
Authority also serves the conventional
/connect/token,/connect/introspect, and/connect/revokealiases through OpenIddict./connect/authorizeis mapped directly in Authority to the custom interactive login shell so browser clients using the Platform-advertised URL do not fall through to the SPA/404 path.
Operational and administrative endpoints (minimal-API routes in the Authority host):
| Path | Method(s) | Scope (StellaOpsScopes) | Notes |
|---|---|---|---|
/health, /ready | GET | anonymous | Liveness/readiness incl. identity-provider health. |
/buildinfo.json | GET | anonymous | Build/version drift signal. |
/.well-known/openapi | GET | anonymous | OpenAPI discovery. |
/api/v1/authority/revocation/status | GET | — | Revocation bundle status. |
/api/v1/tenants/{tenantId}/compliance-profile | GET | authority:tenants.read | Source-owned nullable compliance profile. |
/api/v1/tenants/{tenantId}/assurance-packs | GET | authority:tenants.read, policy:read, or policy:audit | Tenant-enabled assurance packs + readiness reasons; the required tenant header must match the path tenant. |
/api/v1/tenants/{tenantId}/submission-authorizations | GET | authority:tenants.read | Runtime-safe operator submission authorization. |
/console/tenants, /console/profile, /console/token/introspect | GET/POST | ui.read (+ authority:tenants.read for tenants) | Console read surface. |
/console/vuln/*, /console/vex/statements | GET/POST | ui.read + advisory:read/vex:read | /console/vex/events fails closed with 501 vex_events_stream_unsupported. |
/console/admin/*, /api/admin/users (legacy alias) | various | ui.admin group + per-route authority:* scopes | Tenant/user/role/client/token/audit admin; mutations require RequireFreshAuth() and are Audited(...). |
/console/admin/identity-providers/* | GET/POST/PUT/DELETE | ui.admin + `authority:idp.read | write` |
/console/admin/branding | GET/PUT/POST | ui.admin | Branding read/update/preview. |
/internal/* | POST/GET | bootstrap API key (BootstrapApiKeyFilter) | Bootstrap users/clients/invites, service-account inventory/revocations, signing/ack-token rotation, plugin reload — gated by Authority:Bootstrap:Enabled. |
/permalinks/vuln, /notify/ack-tokens/*, /vuln/workflow/*, /vuln/attachments/tokens/*, /advisory-ai/remote-inference/logs | POST | token-signer surfaces | Signed-token issue/verify and consent logging. |
The admin audit list endpoint (GET /console/admin/audit) is deprecated (Sunset 2027-10-19) with successor GET /api/v1/audit/events?modules=authority on Timeline. The compatibility proxy preserves the authenticated tenant and decoded filters, and its shared Timeline client authenticates the service hop with a short-lived signed identity envelope carrying only timeline:read. A missing envelope key fails before HTTP; upstream failures return a sealed 502 timeline_audit_unavailable response rather than exposing transport or storage detail.
Scope catalog
- The canonical scope set is
StellaOps.Auth.Abstractions/StellaOpsScopes.cs— the JWT authorization surface (StellaOpsScopes.Allis reflection-built from the public string consts and registered with OpenIddict alongsideopenid/email/profile/offline_access). - Examples:
authority:tenants.read|write,authority:users.read|write,authority:roles.read|write,authority:clients.read|write,authority:tokens.read|revoke,authority:branding.read|write,authority:idp.read|write,authority.audit.read,authority.revocation.read,ui.read,ui.admin, plus per-module scopes (policy, vuln, vex, advisory, graph, scanner, signer, attest, orch, packs, export, notify, crypto, etc.). - Scheduler uses the canonical claim values
scheduler:readandscheduler:operate;orch:*claims do not authorize Scheduler. Interactive Release Operations Steward tokens may carry both Scheduler claims, while Service Release Contributor tokens may carryscheduler:readonly. The Console must derive Scheduler visibility and controls from the issuedscheduler:*claims rather than role labels ororch:*aliases. - The four professional interactive roles use one canonical
AuthorityInteractiveRoleGrantCatalogfor both Console Admin role display and authorization-code issuance. Executive Assurance Viewer and Security Risk Manager tokens are intersected with their respective assurance-read and risk-analysis bundles, so unrelatedui.admin, release write/publish, operate, and approve scopes are stripped even when the Console client requests them. The Security Risk Manager bundle includes tenant-scopedregistry:readfor the Images inventory; it does not grant registry plan/cache administration or integration writes. vuln:read(StellaOpsScopes.VulnRead) is[Obsolete]— prefervuln:view(VulnView).- The OpenAPI auth spec is
src/Authority/StellaOps.Api.OpenApi/authority/openapi.yaml.
Integrations & dependencies
- Signer/Attestor for PoE and OpTok introspection.
- CLI/UI for login flows and token management.
- Scheduler/Scanner for machine-to-machine scope enforcement.
Operational notes
- PostgreSQL (schema
authority) for tenant, client, and token state, auto-migrated on startup from the embeddedMigrations/**/*.sqlresources inStellaOps.Authority.Persistence(per AGENTS.md §2.7;AddAuthorityPostgresStoragewiresAddStartupMigrations). The legacypostgres-init/04-authority-schema.sqlis a first-run fallback only. - Core tables (
Migrations/001_v1_authority_baseline.sql— the collapsed pre-1.0 chain; the old per-feature files sit underMigrations/_archived/pre_1.0/and are excluded from embedding):authority.tenants,users,roles,permissions,role_permissions,user_roles,api_keys,tokens,refresh_tokens,sessions,bootstrap_invites,service_accounts,clients,client_tenants,revocations,login_attempts,oidc_tokens,oidc_refresh_tokens,revocation_export_state,verdict_manifests. (The deprecatedaudit,airgap_audit, andoffline_kit_audittables are created and then dropped inside the same baseline — audit lives intimeline.unified_audit_events.) Most tenant-scoped tables are RLS-protected viaauthority_app.require_current_tenant()(session varapp.tenant_id).S*-prefixed migrations are scope/seed/client migrations applied whenAuthority:Bootstrap:Enabledis true; the collapsed seed baseline isS001_v1_authority_operational_baseline.sql. - Non-local production runtime must not rely on in-memory/null persistence defaults. Use PostgreSQL for Authority/IssuerDirectory, Valkey-backed DPoP state, and file or messaging Auth client token caches. In-memory harnesses are Development/Testing only unless a documented compatibility gate is set.
- Authority store interfaces are owned by
StellaOps.Authority.Persistence.Stores; the in-memory store namespace contains only local/test implementations and the compatibility driver shim. - Standard plugin bootstrap provisioning retries transient storage failures during startup so first-party local clients converge after PostgreSQL becomes reachable; the first human admin is created through setup, not pre-seeded.
- Signing key material is loaded from pluggable sources (
IAuthoritySigningKeySource): a file source (FileAuthoritySigningKeySource) is always registered, and a KMS source (KmsAuthoritySigningKeySource, file-backedAddFileKms) is added whensigning.keySourceiskms(which also requiressigning.keyPassphrase). Rotation runbook:operations/key-rotation.md. - Telemetry: OpenTelemetry resource
service.name = stellaops-authority,service.namespace = stellaops; ActivitySource and Meter both namedStellaOps.Authority(AuthorityTelemetry). Monitoring runbook (operations/monitoring.md) and offline-import Grafana JSON (operations/grafana-dashboard.json).
Related resources
- Backup & restore:
operations/backup-restore.md - Key rotation:
operations/key-rotation.md - Monitoring:
operations/monitoring.md(Grafana JSON for offline import:operations/grafana-dashboard.json) - Bootstrap modes:
operations/bootstrap-modes.md - Break-glass account:
operations/break-glass-account.md - Crypto-provider contract:
crypto-provider-contract.md - Tenant model:
tenant-model.md - Gap-remediation packages:
gaps/2025-12-04-auth-gaps-au1-au10.md,gaps/2025-12-04-rekor-receipt-gaps-rr1-rr10.md
Backlog references
AUTH-POLICY-20-001/002follow-ups insrc/Authority/StellaOps.Authority/TASKS.md.
Epic alignment
- Epic 1 – AOC enforcement: enforce OpTok scopes and guardrails supporting raw ingestion boundaries.
- Epic 2 – Policy Engine & Editor: supply policy evaluation/principal scopes and short-lived tokens for evaluator workflows.
- Epic 4 – Policy Studio: integrate approval/promotion signatures and policy registry access controls.
- Epic 14 – Identity & Tenancy: deliver tenant isolation, RBAC hierarchies, and governance tooling for authentication.
Implementation Status
Epic milestones:
- Epic 1 (AOC enforcement) — Complete. OpTok scopes, guardrails, AOC role templates, and scope policies operational.
- Epic 2 (Policy Engine & Editor) — Complete. DPoP validation and mTLS sender-constraint flows operational.
- Epic 4 (Policy Studio) — Complete. Pack-signing policies, approval RBAC, CLI CI token scopes, and audit logging delivered.
- Epic 14 (Identity & Tenancy) — In progress. Tenancy contract published; sovereign crypto-provider integration ongoing.
- Attestation support — Planned. DSSE predicate types and verification helpers pending upstream Signer/Provenance dependencies.
Key technical decisions:
- DPoP validation on token grants with cnf.jkt inheritance for interactive tokens
- Refresh grants enforce original client cert with x5t#S256 metadata persistence
- Sealed-mode CI gating refuses tokens when sealed install lacks confirmation
- Tenant-scope contract published for cross-module coordination
Risks & mitigations:
- Sovereign crypto keystore migration in progress; key-loading path updates required.
- DSSE predicate schema draft pending coordination with the Signer guild.
- Verification helpers depend on the Provenance harness.
