Skip to main content

Spring Auth-Proof Mode

Overview

Spring includes a dedicated auth-proof flow for generated endpoints so you can verify authentication and authorization behavior in local development with explicit 200, 401, and 403 outcomes.

warning

Auth-proof mode is a local development aid that uses header-based identity emulation. It is not a production authentication design.

Before You Begin

Before following this guide:

  • start from a local Spring sample environment
  • keep this page scoped to development validation only
  • use Host Architecture for the broader generated-host wiring context

Step 1: Enable Auth-Proof Mode

Set Spring__AuthProofMode=true before launching Spring.AppHost.

When using the repository helper script, use:

./run-spring.ps1 -LocalAuth On

The script now reads Aspire startup output and prints the runtime login URL when detected from Aspire logs. By default, token values are hidden; use -ShowDashboardToken to print the runtime token.

To run Spring with local auth handling disabled (default demo mode), use:

./run-spring.ps1 -LocalAuth Off

When enabled, AppHost sets SpringAuth__Enabled=true for spring-gateway.

When not set (or set to false), Spring still wires authentication and authorization middleware, but the local dev authentication handler returns NoResult and does not establish a principal. Endpoints decorated with generated authorization metadata therefore return 401/403 based on normal ASP.NET authorization behavior.

Step 2: Set Identity Override Headers

When local dev auth is enabled, Spring.Gateway reads these headers:

HeaderPurposeExample
X-Spring-AnonymousForces no authenticated principal for the requesttrue
X-Spring-UserOverrides user identifierauth-proof-user
X-Spring-RolesComma-separated roles (none means empty role set)auth-proof-operator
X-Spring-ClaimsClaim pairs (type=value) separated by , or ;spring.permission=auth-proof

Header precedence is request header over configured defaults.

When local dev auth is enabled, Spring only honors these override headers for local loopback requests.

Source:

Expected Results

Spring auth-proof mode demonstrates generated authorization behavior across all three endpoint categories:

CategoryEndpointAuthorization metadataIdentity exampleExpected status
CommandPOST /api/aggregates/auth-proof/{id}/authenticated[GenerateAuthorization]X-Spring-Anonymous: true401
CommandPOST /api/aggregates/auth-proof/{id}/role[GenerateAuthorization(Roles = "auth-proof-operator")]X-Spring-Roles: none403
CommandPOST /api/aggregates/auth-proof/{id}/role[GenerateAuthorization(Roles = "auth-proof-operator")]X-Spring-Roles: auth-proof-operator200
SagaGET /api/sagas/auth-proof/{sagaId}/status[GenerateAuthorization(Roles = "auth-proof-operator")]X-Spring-Anonymous: true401
SagaGET /api/sagas/auth-proof/{sagaId}/status[GenerateAuthorization(Roles = "auth-proof-operator")]X-Spring-Roles: none403
SagaGET /api/sagas/auth-proof/{sagaId}/status[GenerateAuthorization(Roles = "auth-proof-operator")]X-Spring-Roles: auth-proof-operator200
ProjectionGET /api/projections/auth-proof/{id}[GenerateAuthorization(Policy = "spring.auth-proof.claim")]X-Spring-Anonymous: true401
ProjectionGET /api/projections/auth-proof/{id}[GenerateAuthorization(Policy = "spring.auth-proof.claim")]no matching claim403
ProjectionGET /api/projections/auth-proof/{id}[GenerateAuthorization(Policy = "spring.auth-proof.claim")]X-Spring-Claims: spring.permission=auth-proof200

Source:

SignalR Subscription Behavior

Auth-proof mode also exercises projection subscription authorization through InletHub.

  • Projection authorization metadata comes from projection type attributes discovered during ScanProjectionAssemblies(...).
  • With Spring auth-proof mode enabled, the server uses generated API force mode and keeps AllowAnonymousOptOut = true.
  • In this configuration, MapInletHub() does not require hub-level authorization metadata; authorization is evaluated per SubscribeAsync(...) call.
  • Subscription denials return a generic client-safe HubException message: Subscription denied..

Source:

Verify

Run the auth-proof matrix tests:

dotnet test ./samples/Spring/Spring.L2Tests/Spring.L2Tests.csproj -c Release --filter "FullyQualifiedName~AuthProofAuthorizationIntegrationTests"

These tests validate all required scenarios across command, saga, and projection endpoints:

  • anonymous identity -> 401
  • authenticated identity missing required role/claim -> 403
  • authenticated identity with required role/claim -> 200

Source:

Troubleshooting

SymptomLikely causeCheck
401 UnauthorizedNo authenticated principal was establishedEnsure X-Spring-Anonymous is absent or false; for local header identity, ensure SpringAuth__Enabled=true
403 ForbiddenPrincipal authenticated but missing required role/claimVerify X-Spring-Roles and X-Spring-Claims match endpoint requirements
401 when auth-proof mode is offLocal dev handler did not create an identityConfirm Spring__AuthProofMode=true before startup
Subscription denied. during projection subscribeProjection metadata requires auth and current identity does not satisfy policy/roles/schemesVerify simulated persona headers and projection auth attributes
Dashboard token is hidden in script outputToken output is intentionally redacted by defaultRe-run with ./run-spring.ps1 -LocalAuth On -ShowDashboardToken to print runtime token

Summary

  • Auth-proof mode is a dev-only switch that enables local header-based identity simulation.
  • Generated auth metadata on auth-proof endpoints enforces 401/403/200 outcomes as defined by ASP.NET authorization.
  • L2 tests validate the command, saga, and projection authorization matrix.

Next Steps