Console
Browse docs

Decisions

Maintainer documentation — you don't need this to use or operate the platform.

The design decisions behind the Access contract, each with the evidence that backs it. It is written for maintainers; the specification is normative, and platform decisions defines this table and when a decision changes the contract.

Read byRepository maintainer

#QuestionDecisionStated inStatusEvidence
1Where does multi-tenancy live?In Access, never in the gateway. A gateway keeps one provider and one Access deployment, so one gateway deployment serves one tenant.§1.4resolvedsrc/domains/identity/tenant.ts, test/contract/shared-client.test.ts
2Is Access an OpenID Connect provider or client?Both: a client of each tenant's provider and a provider for the gateway. The gateway does not need to know.—resolvedsrc/domains/provider/service.ts, src/domains/provider/discovery.ts
3What keys an identity mapping?(tenant, provider, subject). Never the e-mail: it is mutable and not an identity. The provider is in the key because two providers of a tenant hand out the same sub.§6.2resolvedsrc/domains/identity/mapping.ts, test/contract/login.test.ts
4Is a principal created at first login?Only when the tenant has auto_provision = true, and then with no grant: login succeeds, access does not.§6.4resolvedsrc/domains/identity/mapping.ts, test/contract/login.test.ts
5What decides access?The grants table alone. Request roles are a token snapshot; reading them would honor a revoked grant until the next login.§8.4resolvedsrc/domains/authorization/decision.ts, test/contract/decisions.test.ts
6Does Access cache decisions?No. The table is the truth, the query is one statement over indexed tables, and revocation latency is the gateway's cache TTL.§8.6resolvedsrc/domains/authorization/decision.ts, test/integration/decision-rule.test.ts
7How many administrative endpoints?Twenty-one (thirteen that change, eight that list) plus one that reads the audit. Nothing else changes tenants, principals or grants, so the audit is complete.§10resolvedsrc/domains/administration/service.ts, test/contract/administration.test.ts
8Why store the authorization code instead of making it self-contained?A self-contained code can be redeemed twice within its lifetime. Storing it makes it single use, which the gateway relies on.§5.5resolvedsrc/domains/provider/code.ts, test/contract/login.test.ts
9Who holds a refresh token?Only a client that keeps a session of the caller. The gateway holds none: it keeps a session of its own and does not read the data with the token of the caller. The console asks for one with the scope offline_access, and renews the token of the caller on the server, so the caller signs in once and not every five minutes.§7.6resolvedsrc/domains/provider/refresh.ts, src/domains/provider/tokens.ts
10Why is the denial reason free text?The gateway hides it and only counts it. The reason vocabulary lets the gateway's count separate a missing role from every other denial.§8.7resolvedsrc/domains/authorization/decision.ts, test/contract/refusals.test.ts
11Which address does the audit hold?The address of the socket, unless the deployment is behind an ingress that is the only way in (ACCESS_INGRESS_ONLY): the ingress reports the address of the caller in x-real-ip, and the audit names the operator that made the change. The limiter of the administration keeps the address of the socket: a header is a value the caller controls.§10.1resolvedsrc/domains/forwarding/address.test.ts, test/contract/caller-address.test.ts
12Where does the registration of a provider live?In a table of its own, tenant_providers, and not in the row of the tenant. A tenant signs its people in at one or more providers, and the row of the tenant keeps the registration of the default one only, because that is what the administration writes. The slug of a provider never changes: a principal carries it.§3.11resolvedsrc/platform/postgres/providers.ts, src/domains/identity/provider-driver.ts, test/integration/providers.test.ts
13How does a tenant with several providers let its callers sign in?At its default provider: the registration of the tenant is the default provider, and a caller is never asked to choose between the providers of a tenant that has one. A tenant whose default provider is disabled and that has several providers answers with a page that lists them, and the choice is the caller's.§5.2.1resolvedsrc/app/pages.ts, src/domains/identity/service.ts, test/contract/login.test.ts
14How does a local provider hold its own accounts?With a table of its own, local_credentials, and an argon2id verifier per account. The answer of a refused sign-in never says whether the address exists: the service verifies the password against nothing when the address names no account, and it counts the failures of the address and of the account.§3.12, §5.4.2resolvedsrc/domains/identity/local-authenticator.ts, src/platform/postgres/credentials.ts, test/contract/local-login.test.ts
15How does a shared client know the tenant of a login?By the address of the caller: Access asks for it with a page of its own, and the domain of the address names the tenant with that email_domain. The page names no tenant of the platform, and an address that names no tenant is the default tenant of the platform.§5.2.2resolvedsrc/app/discovery.ts, src/domains/identity/tenant.ts, test/contract/discovery.test.ts
16Who may route the addresses of a domain to a tenant?The owner of the domain, or the operator of the platform. A route waits for its proof: the owner publishes a TXT record of _access of the domain that carries the challenge of the route, and the operator of the platform vouches for a domain instead. A tenant proves its own domains and nobody else's, and a route that waits routes nothing.§3.13, §10.18resolvedsrc/domains/administration/routes.ts, src/platform/bun/dns.ts, test/contract/routes.test.ts