AUTH4D-8 tenant and application policy

This ticket adds package services and policy helpers; it does not enable management or authentication routes. Callers resolve a customer tenant by its required tenantId and resolve a client using the compound (tenantId, clientId) key. The configured auth origin forms the issuer; request host and forwarded-host headers are never used. Suspended tenants and disabled or confidential tenant clients fail closed in resolveAuthenticationApplication. Authentication starts and refresh requests use the same resolver before continuing. Security-sensitive D1 reads use first-primary sessions.

Application policy requires exact registered redirect URI and browser Origin matches. Redirects must use HTTPS, except explicit loopback HTTP for local development; fragments, credentials, and wildcards are rejected. Origins must be canonical origins and follow the same HTTPS/loopback rule. All requested scopes and grant types must be enabled for that application. Signup intent is denied when the trusted tenant signup setting is false. Provider login is allowed only for enabled providers; email and Discord read their enablement from tenant-scoped provider configuration, while guest login is a built-in provider. A trusted provider-policy adapter may disable guest login for a tenant.

The frozen foundation schema does not contain a signup-enabled column. The tenancy repository accepts a trusted signup-setting adapter and defaults to enabled until a later schema-owned ticket adds persistence. No caller-supplied public configuration can set this value. Its public projection only contains tenant/client identifiers, display name, issuer, client type, scopes, signup state, and enabled provider names; it omits client secret hashes, provider client IDs, secret bindings, and all credential material.

Customer application management creates browser or native public clients only. Native clients use device authorization and cannot register browser redirects or origins. Confidential server clients are reserved for the console/control-plane integration and are not created or exposed by ordinary customer tenant operations.

Project membership policy

Membership capability checks are tenant-bound and never grant /management/* control-plane access. Management routes still require a control-plane actor, the immutable management audience, and the route’s required management scope.

Project role Permissions
owner All tenant, client, user, session, and audit permissions
admin Tenant read; client, user, and session read/write or revoke; audit read
viewer Tenant, client, user, session, and audit read

Owner transfer is intentionally not part of ordinary role assignment. Owners may grant admin or viewer; admins may grant viewer; viewers cannot assign roles. The existing shared membership table stores owner and member; its member rows project to least-privileged viewer. Admin grants are accepted by the policy helper for later management-membership storage, without changing the frozen shared schema.

Source: docs/api-spec/auth4d-8.md