Per-environment tenancy
Per-environment tenancy
Cbox ID is environment-scoped: every organization lives inside exactly one
environment (a plane such as production or staging, keyed by a ULID with a
slug / name). Cbox Billing is environment-aware without breaking
single-environment deployments — the design is additive and backward-compatible.
The model
| Concern | How Cbox Billing handles it |
|---|---|
| Tenant primary key | Stays the org id. An org belongs to exactly one environment, so its id is already globally unique — there is no breaking composite key. |
| Home environment | Recorded on organizations.environment_key — the plane billing groups the org under. |
| Active environment (session) | Resolved from the login's environment claim, falling back to the configured default. |
The additive column
The migration adds a nullable organizations.environment_key and backfills every
existing row to the single configured default, so nothing changes for a
single-environment deployment. The org id remains the tenant key; environment_key is
a grouping/filter dimension, not part of the identity.
The default fallback
config('cbox-id-client.environment_default') (env CBOX_ID_ENVIRONMENT_DEFAULT,
default default) is the single plane every org groups under until Cbox ID emits an
environment claim. The resolver
(EnvironmentContext)
resolves the active environment from the claim and falls back to this default —
mirroring Cbox ID's own host→default fallback, so a host-less single-tenant deploy
Just Works. The active plane is surfaced as a small chip in the console top bar.
Stamping on login
When a login carries an environment claim, it is stamped on the org's row the
first time it is seen. If the org already has a recorded environment and the claim
disagrees, the mismatch is logged and the recorded value kept — billing never
silently moves a tenant between planes. A login with no claim stamps the org to
the configured default.
The principal
(AuthedUser)
carries environment and environmentName, populated from the environment /
environment_name claims when present, and null otherwise.
The signal dependency
Per-environment separation lights up once Cbox ID emits the
environmentclaim.
Today the claim does not appear in the id_token or userinfo, so every org groups under the single default and the feature is inert — a coordinated Cbox ID release is required before multiple environments are distinguished. Until then the behaviour is identical to a single-plane deployment.
Related documentation
- OIDC login — the sign-in flow that carries the claim.
- Federated RBAC manifest — the peer defensive claim (
permissions). - Configuration → Environment — the
CBOX_ID_*keys.