Aspire Hosting Integration
The Cratis.AuthProxy.Aspire NuGet package adds first-class .NET Aspire support for AuthProxy.
Instead of configuring environment variables by hand, you wire up authentication, tenancy, and
service routing with a concise fluent API in your AppHost.
Installation
Section titled “Installation”dotnet add package Cratis.AuthProxy.AspireAdding AuthProxy as a container resource
Section titled “Adding AuthProxy as a container resource”This is the typical path for external consumers who run AuthProxy from Docker Hub:
var authproxy = builder.AddAuthProxy("authproxy", tag: "latest") .WithHttpEndpoint(port: 8080) .WithBackend("main", apiResource) .WithFrontend("main", webResource) .WithOidcProvider( "Microsoft", OidcProviderType.Microsoft, authority: "https://login.microsoftonline.com/<tenant-id>/v2.0", clientId: "<client-id>", clientSecret: "<client-secret>") .WithHostTenantResolution();AddAuthProxy creates an AuthProxyResource backed by the cratis/authproxy Docker Hub image.
Pin tag to a specific release in production environments — the default "latest" is convenient
for local development.
Adding AuthProxy as a project resource
Section titled “Adding AuthProxy as a project resource”When working inside the AuthProxy repository itself (or in a monorepo that includes AuthProxy
source), use AddProject with the same extension methods:
var authproxy = builder.AddProject<Projects.AuthProxy>("authproxy") .WithBackend("main", apiResource) .WithFrontend("main", webResource);All With* methods work on any IResourceBuilder<T> where T : IResourceWithEnvironment,
so you can mix container and project resources freely.
Services
Section titled “Services”Use WithBackend and WithFrontend to register the resources that AuthProxy should proxy:
authproxy .WithBackend("main", apiResource) .WithFrontend("main", webResource);Both methods accept an optional endpointName parameter (defaults to "http") that selects
which endpoint from the target resource to forward to.
Identity details resolution
Section titled “Identity details resolution”For each service with a backend, AuthProxy calls GET {baseUrl}/.cratis/me after authentication
to enrich the identity cookie. This behaviour is on by default. To disable it for a specific
service, pass resolveIdentityDetails: false to WithBackend:
authproxy .WithBackend("reporting", reportingApi, resolveIdentityDetails: false) .WithFrontend("reporting", reportingWeb);See Services for the underlying configuration model.
Anonymous paths
Section titled “Anonymous paths”Declare the request paths on a service that should be served without a session — a magic-link
landing page, a signed-token report, a public webhook receiver. Call WithAnonymousPaths once
per service; each call accumulates entries:
authproxy.WithAnonymousPaths("main", "/welcome", "/api/webhooks/payments");Each entry is a rooted path prefix, matched case-insensitively on segment boundaries — /welcome
covers /welcome and /welcome/anything, but not /welcomex. AuthProxy still strips inbound
identity headers on these paths and the application remains responsible for authorizing them.
See Anonymous paths for the full matching rules and what the flag does and does not change.
Authentication
Section titled “Authentication”OIDC providers
Section titled “OIDC providers”authproxy.WithOidcProvider( name: "Contoso AD", type: OidcProviderType.Microsoft, authority: "https://login.microsoftonline.com/<tenant-id>/v2.0", clientId: "<client-id>", clientSecret: "<client-secret>", scopes: ["api://my-api/.default"]);Call WithOidcProvider once per provider. Multiple calls produce a provider-selection page.
The OidcProviderType enum contains well-known provider brands:
| Value | Description |
|---|---|
Custom | Generic / unknown provider. |
Microsoft | Microsoft Identity Platform (Azure AD / Entra ID). |
Google | Google Identity. |
GitHub | GitHub OAuth / OIDC. |
Apple | Apple Sign-In. |
OAuth 2.0 (non-OIDC) providers
Section titled “OAuth 2.0 (non-OIDC) providers”For providers that do not expose an OIDC discovery document, use WithOAuthProvider:
authproxy.WithOAuthProvider( name: "GitHub", type: OidcProviderType.GitHub, authorizationEndpoint: "https://github.com/login/oauth/authorize", tokenEndpoint: "https://github.com/login/oauth/access_token", userInformationEndpoint: "https://api.github.com/user", clientId: "<client-id>", clientSecret: "<client-secret>", scopes: ["user:email"], claimMappings: new Dictionary<string, string> { ["sub"] = "id", ["name"] = "login", ["email"] = "email" });See Authentication for the full configuration reference.
Tenant resolution
Section titled “Tenant resolution”Add one or more resolution strategies. They run in order until a tenant is matched:
| Method | Strategy |
|---|---|
WithHostTenantResolution() | Matches the request host against configured tenant domains. |
WithSubHostTenantResolution() | Derives the tenant from the first subdomain (e.g. acme.example.com → acme). |
WithClaimTenantResolution(claimType?) | Reads a claim from the authenticated user. |
WithRouteTenantResolution(pattern) | Extracts a source identifier from the request path by regex. |
WithSpecifiedTenantResolution(tenantId) | Pins all requests to one fixed tenant (single-tenant deployments). |
WithDefaultTenantResolution(tenantId) | Fallback when no other strategy resolves a tenant. |
WithSelectionTenantResolution() | Reads the tenant from the cookie set by the tenant-selection page. |
authproxy .WithSubHostTenantResolution() .WithDefaultTenantResolution("lobby");See Tenancy for detailed strategy documentation.
Tenant verification
Section titled “Tenant verification”After resolution, AuthProxy can confirm the tenant exists by calling your back-end. You can pass a raw URL template or reference an Aspire service resource directly:
// Raw URL templateauthproxy.WithTenantVerification("https://platform.example.com/api/tenants/{tenantId}");
// Aspire resource reference — endpoint is resolved automaticallyauthproxy.WithTenantVerification(platformApi, "/api/tenants/{tenantId}");AuthProxy issues a GET to the resolved URL. A 200 response lets the request proceed; 404 or
any error serves the tenant-not-found.html page.
Tenant selection
Section titled “Tenant selection”When users can be members of more than one tenant, the Selection strategy presents a
tenant-selection page after login. You can pass a raw URL or reference an Aspire service resource:
// Raw URLauthproxy.WithSelectionTenantResolution( tenantsEndpoint: "https://platform.example.com/api/tenants/selectable");
// Aspire resource reference — endpoint is resolved automaticallyauthproxy.WithSelectionTenantResolution(platformApi, "/api/tenants/selectable");AuthProxy calls the endpoint after login and, if more than one tenant is returned, serves the
built-in select-tenant.html page. If only one tenant is returned the selection page is
skipped and the user is redirected immediately.
The endpoint must return a JSON array of { "id": "...", "name": "..." } objects.
See Tenant Selection Page for details on building a custom selection page and the full flow.
Invites, registration and lobby
Section titled “Invites, registration and lobby”Core invite configuration
Section titled “Core invite configuration”Configure the invite system with the RSA public key and exchange endpoint. You can pass a raw URL or reference an Aspire service resource for the exchange endpoint:
// Raw URLauthproxy.WithInvite( publicKeyPem: File.ReadAllText("invite-public-key.pem"), exchangeUrl: "https://studio.example.com/internal/invites/exchange", issuer: "https://studio.example.com", audience: "authproxy", tenantClaim: "tenant_id", subjectAlreadyExistsUrl: "https://app.example.com/errors/account-already-exists");
// Aspire resource reference — exchange endpoint URL is resolved automaticallyauthproxy.WithInvite( publicKeyPem: File.ReadAllText("invite-public-key.pem"), exchangeServiceResource: studioApi, exchangeRoute: "/internal/invites/exchange", issuer: "https://studio.example.com", tenantClaim: "tenant_id");| Parameter | Required | Description |
|---|---|---|
publicKeyPem | ✓ | PEM-encoded RSA public key to verify invite token signatures. |
exchangeUrl | ✓ | Endpoint called after login to exchange the invite token. |
issuer | – | Expected iss claim. Omit to skip issuer validation. |
audience | – | Expected aud claim. Omit to skip audience validation. |
tenantClaim | – | Claim that carries the tenant ID for tenant-issued invite detection. |
subjectAlreadyExistsUrl | – | Redirect URL when the exchange endpoint returns HTTP 409. Omit to serve the built-in page. |
Claim forwarding
Section titled “Claim forwarding”To propagate invite-token claims into the principal sent to /.cratis/me endpoints, call
WithInviteClaimForwarding once per claim:
authproxy .WithInviteClaimForwarding("organization_id", toClaimType: "organization") .WithInviteClaimForwarding("invited_by");When toClaimType is omitted the original claim type is preserved.
The lobby is the service users are redirected to when no tenant can be resolved — typically an onboarding application. At minimum, configure the lobby frontend:
authproxy .WithLobbyFrontend(lobbyResource) .WithLobbyBackend(lobbyApiResource); // optionalWithLobbyFrontend and WithLobbyBackend both accept an optional endpointName parameter
(defaults to "http").
Registration
Section titled “Registration”To send users through the AuthProxy registration bootstrap flow, configure a lobby registration URL:
authproxy.WithLobbyRegistration(lobbyResource, "/register");
// or use a raw URLauthproxy.WithLobbyRegistration("https://lobby.example.com/register");This sets Cratis:AuthProxy:Invite:Lobby:Registration:BaseUrl. Users who visit /register
authenticate through AuthProxy and are then redirected to that registration URL.
See Lobby for the onboarding flow walkthroughs.