Skip to content

Tenancy

AuthProxy resolves a tenant ID string from each incoming request and stores it in the request context. Downstream services receive the resolved tenant ID via the Tenant-ID header.


Resolution strategies run in order until one strategy resolves a tenant. Configure them under Cratis:AuthProxy:TenantResolutions:

{
"Cratis": {
"AuthProxy": {
"TenantResolutions": [
{ "Strategy": "Host" },
{ "Strategy": "Claim", "Options": { "ClaimType": "tid" } }
]
}
}
}
StrategyDescription
HostUses the request host and matches it against configured tenant Domains / SourceIdentifiers.
ClaimReads a claim value from the authenticated user and matches it against configured tenant SourceIdentifiers.
RouteExtracts a source identifier from the request path by regex and matches it against configured tenant SourceIdentifiers.
SpecifiedResolves directly to a fixed tenant ID string from configuration.
DefaultResolves directly to a fallback tenant ID string from configuration.
SubHostResolves directly from subhost convention, for example acme.example.com -> acme.
SelectionResolves from the selected-tenant cookie set by the tenant-selection page flow.

{
"Strategy": "Claim",
"Options": {
"ClaimType": "tid"
}
}

If ClaimType is omitted, AuthProxy falls back to reading X-MS-CLIENT-PRINCIPAL.

This is also how you resolve a tenant carried on an AuthProxy-issued client-credentials bearer token — point ClaimType at cratis/tenant. See Resolving a tenant from the verification response.


{
"Strategy": "Route",
"Options": {
"Pattern": "^/tenant/(?<sourceIdentifier>[^/]+)"
}
}

The regex must expose a named group called sourceIdentifier.


{
"Strategy": "Specified",
"Options": {
"TenantId": "acme"
}
}

{
"Strategy": "Default",
"Options": {
"TenantId": "lobby"
}
}

{
"Strategy": "SubHost",
"Options": {
"ParentHost": "example.com",
"VerificationUrlTemplate": "https://platform.example.com/internal/tenants/{tenantId}"
}
}
PropertyTypeDescription
ParentHoststringParent host suffix used to extract the tenant ID from the request host.
VerificationUrlTemplatestringOptional strategy-specific verification URL template. Overrides the global TenantVerification.UrlTemplate for this strategy.

The strategy strips the configured ParentHost suffix from the incoming request host to derive the tenant ID.

Given ParentHost: "example.com":

Request hostResolved tenant IDNotes
acme.example.comacmeSingle-segment subhost — resolved successfully.
contoso.example.comcontosoSingle-segment subhost — resolved successfully.
foo.bar.example.comMulti-segment subhost rejected — not resolved.
example.comNo subhost present — not resolved.
other.comHost does not end with .example.com — not resolved.

The resolved subhost string becomes the tenant ID directly. No Tenants dictionary lookup is performed — unlike Host, Claim, and Route strategies, SubHost does not match a source identifier against a pre-configured list. This is intentional: SubHost is designed for environments where tenants are provisioned dynamically (for example SaaS platforms where each customer gets their own subdomain).

For interactive authentication flows, AuthProxy stores SubHost strategy metadata in protected authentication state when it issues the provider challenge. On callback, AuthProxy restores this metadata and redirects to the tenant subhost.

This enables a shared callback endpoint (for example auth.cratis.studio) while returning the user to the original tenant host (for example nova.cratis.studio).

Because there is no registry lookup to prove the tenant exists, you should configure VerificationUrlTemplate to have AuthProxy call your back-end to confirm the tenant is valid before forwarding the request:

{
"Strategy": "SubHost",
"Options": {
"ParentHost": "example.com",
"VerificationUrlTemplate": "https://internal-api.example.com/tenants/{tenantId}"
}
}

AuthProxy replaces {tenantId} with the resolved subhost value and expects a 200 response. Any other response causes the request to be rejected with tenant-not-found.html. See Tenant verification for full response handling details.


{
"Strategy": "Selection",
"Options": {
"TenantsEndpoint": "https://platform.example.com/api/tenants/selectable"
}
}
PropertyTypeDescription
TenantsEndpointstringAbsolute URL for the endpoint that returns selectable tenants for the current authenticated user. Expected response shape is an array of { "id": "...", "name": "..." } objects.

When this strategy is configured and no .cratis-tenant cookie exists yet, AuthProxy calls TenantsEndpoint, sets the .cratis-tenants cookie, and serves select-tenant.html. The page links back to /.cratis/select-tenant?tenantId=<id>&returnUrl=<path>, and AuthProxy validates the selected tenant against the endpoint response before writing the .cratis-tenant cookie.


For Host, Claim, and Route, AuthProxy resolves a source identifier and then looks up the tenant ID in Cratis:AuthProxy:Tenants.

{
"Cratis": {
"AuthProxy": {
"Tenants": {
"acme": {
"Domains": ["acme.example.com"],
"SourceIdentifiers": ["acme", "tenant-acme"]
},
"contoso": {
"Domains": ["contoso.example.com"],
"SourceIdentifiers": ["contoso", "tenant-contoso"]
}
}
}
}
}

When no tenant can be resolved and the lobby is configured, AuthProxy redirects the user to the lobby frontend instead of returning 401 Unauthorized.

If no lobby is configured and TenantResolutions is non-empty, AuthProxy returns 401 Unauthorized. When TenantResolutions is empty, the request proceeds without a tenant.


After tenant resolution, AuthProxy can verify that the tenant exists before forwarding the request. This is optional.

{
"Cratis": {
"AuthProxy": {
"TenantVerification": {
"UrlTemplate": "https://platform.example.com/api/tenants/{tenantId}"
}
}
}
}
PropertyTypeDescription
UrlTemplatestringURL template for tenant verification. Use {tenantId} placeholder.
  • 200: tenant exists, request proceeds.
  • 404: tenant does not exist; AuthProxy serves tenant-not-found.html with 404.
  • Any other status or network error: treated as tenant verification failure, and tenant-not-found.html is served.

If a strategy provides a strategy-specific verification URL template (for example SubHost.Options.VerificationUrlTemplate), that template is used instead of the global TenantVerification.UrlTemplate.

When verification fails, AuthProxy serves tenant-not-found.html. See Error pages to override this page.