AppSurface Auth Web/RazorWire Proof
Source of truth
This sample is the five-minute proof for ForgeTrust.AppSurface.Auth.AspNetCore: one host-owned ASP.NET Core policy flows through AppSurface into both a Minimal API response and a RazorWire-facing rendered state.
Your host owns auth. This sample only changes the local proof persona.
Run The Proof
From the repository root:
dotnet run --project examples/auth-web-razorwire-proof/AuthWebRazorWireProofExample.csproj --urls http://127.0.0.1:5058
Open http://127.0.0.1:5058/ and use the persona switch:
| Persona | API status | AppSurface outcome | AppSurface reason | RazorWire-facing state |
|---|---|---|---|---|
anonymous |
401 |
Challenge |
Unauthenticated |
unauthenticated |
viewer |
403 |
Forbid |
Forbidden |
forbidden |
operator |
200 |
Allowed |
None |
allowed |
The two panels should agree for every persona:
Minimal APIshows the JSON-facing status, outcome, reason, and subject.RazorWire-facing staterenders the same policy result as page state.
Curl Parity
The browser switch keeps the selected persona in URL-local proof state. Curl can use X-Proof-User; the header wins over URL state so command-line checks stay deterministic.
curl -i http://127.0.0.1:5058/api/auth-proof
curl -i -H 'X-Proof-User: viewer' http://127.0.0.1:5058/api/auth-proof
curl -i -H 'X-Proof-User: operator' http://127.0.0.1:5058/api/auth-proof
Expected response states:
- No header:
401,Challenge,Unauthenticated, no subject. viewer:403,Forbid,Forbidden, subjectviewer-1.operator:200,Allowed,None, subjectoperator-1.
Unsupported proof users behave like anonymous requests.
What This Sample Proves
- The host registers the local proof authentication handler.
- The host owns the
OperatorsOnlyauthorization policy and registers it withAddAppSurfacePolicy(...). AddAppSurfaceAspNetCoreAuth(...)maps the evaluated ASP.NET Core policy result intoAppSurfaceAuthResult.- The Minimal API endpoint and RazorWire-facing page use the same
IAppSurfaceAspNetCorePolicyEvaluator.AuthorizeAsync("OperatorsOnly")decision path.
For production Minimal API endpoints that only need to enforce a host policy and return API-safe auth failures, prefer RequireSurfacePolicy(...). This sample calls the evaluator directly so /api/auth-proof can return the same canonical outcome matrix that the RazorWire-facing page renders.
What This Sample Is Not
- Not production authentication.
- Not OAuth, OIDC, JWT, cookies, ASP.NET Identity, login, or logout guidance.
- Not challenge, forbid, redirect, sign-in, or sign-out execution.
- Not a replacement for
RequireSurfacePolicy(...)on production Minimal API endpoints. - Not an
AuthGate,AuthView,PermissionGate, or result-bearing RazorWire auth adapter.
Keep the proof-only ProofAuthenticationHandler, URL-local proof state, and persona switch inside this sample. Real applications should keep their existing ASP.NET Core authentication handlers and policies, then let AppSurface observe the populated request principal and named host-policy result.
If Your Result Differs
- Confirm you ran the command from the repository root.
- Confirm the app is listening on
http://127.0.0.1:5058. - Confirm the host calls
UseAuthentication()beforeUseAuthorization(). - Confirm authenticated proof users have a stable
subclaim. Missing subjects are setup failures, not forbidden results. - Confirm the policy name is
OperatorsOnly; missing policy names are setup failures.
For lower-level adapter diagnostics such as missing policy, missing services, and missing subject, see the ASP.NET Core auth bridge example.