Skip to content

IAM — Tenants

Every account, role and user group belongs to exactly one tenant and carries its id as the first segment of its CRN. A device joins only when it is claimed, assigned or attached to a contract; until then it sits in the register's unassigned pool, under a CRN with no tenant in it.

The entry holds what applies to all of them: rootAccess bounds every rule inside — rules sit on roles and on accounts, never on a user group — and enforce2FA reaches every account, though a role or an account may demand a second factor the tenant does not. Writes raise IAM_TENANT_CREATE, IAM_TENANT_UPDATE, IAM_TENANT_REPLACE and IAM_TENANT_DELETE.

POSTCreate a tenant/api/v1/tenant
GETList tenants/api/v1/tenant
GETRead a tenant/api/v1/tenant/:tenantId
GETRead tenant info/api/v1/tenant/:tenantId/info
DELETEDelete a tenant/api/v1/tenant/:tenantId
PATCHUpdate a tenant/api/v1/tenant/:tenantId
PUTReplace a tenant/api/v1/tenant/:tenantId

Create a tenant

Mints the tenant and returns its resource identifier. rootAccess is the ceiling every role and user rule inside the tenant is later held to; omitted it defaults to full rights on the new tenant, and anything wider is refused.

POST/api/v1/tenant

Body

NameDescription
enforce2FAbooleanoptionalWhether all users in this tenant are required to enrol in two-factor authentication
Default: true
allowedOriginsarrayoptionalList of origins permitted to make cross-origin requests to this tenant
Default: []
passwordSecretoptionalCustom secret used to pepper password hashes for this tenant
rootAccessarrayoptionalAccess policies that apply at the root scope of this tenant
identifierThe resource this policy applies to
Alternative 1Resource identifier pattern (CRN), may include wildcards
Alternative 2Resource identifier pattern (CRN), may include wildcards
Alternative 3Resource identifier pattern (CRN), may include wildcards
Alternative 4Resource identifier pattern (CRN), may include wildcards
Alternative 5Resource identifier pattern (CRN), may include wildcards
Alternative 6Resource identifier pattern (CRN), may include wildcards
effectenumAccess policy effect — either allow or deny
Possible values: deny, allow
actionsarrayList of actions permitted by this policy
policyobjectoptionalAdditional constraints for this access policy
enforce2FAbooleanoptionalRequires the subject to have 2FA active before this access is granted
targetoptionalWhere a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Alternative 1Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Possible values: user, role, group
Alternative 2Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
isOwnerbooleanoptionalMarks an owner-relative rule, written as crn#tenant:<id>.user:* and rebound to the holder's own account when the access list is assembled — how a shared role says "your own account" without naming anyone.
namestringShort alphanumeric tenant identifier (slug)
Pattern: ^\w{4,16}$

Response

NameDescription
resourceIdentifierstringUnique Coldwave resource name (CRN) that identifies a resource

Errors

StatusDescriptionBody
403You do not have permission to perform this action
400The requested access permissions exceed what is allowed for this tenantcode: TENANT_NO_SUBSET_ERROR
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50

List tenants

Every tenant the caller may read, filtered one by one rather than gated as a whole — a root administrator sees all of them, an ordinary tenant administrator only their own.

GET/api/v1/tenant

Response

NameDescription
enforce2FAbooleanoptionalWhether all users in this tenant are required to enrol in two-factor authentication
Default: true
rootAccessarrayAccess policies that apply at the root scope of this tenant
identifierThe resource this policy applies to
Alternative 1Resource identifier pattern (CRN), may include wildcards
Alternative 2Resource identifier pattern (CRN), may include wildcards
Alternative 3Resource identifier pattern (CRN), may include wildcards
Alternative 4Resource identifier pattern (CRN), may include wildcards
Alternative 5Resource identifier pattern (CRN), may include wildcards
Alternative 6Resource identifier pattern (CRN), may include wildcards
effectenumAccess policy effect — either allow or deny
Possible values: deny, allow
actionsarrayList of actions permitted by this policy
policyobjectoptionalAdditional constraints for this access policy
enforce2FAbooleanoptionalRequires the subject to have 2FA active before this access is granted
targetoptionalWhere a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Alternative 1Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Possible values: user, role, group
Alternative 2Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
isOwnerbooleanoptionalMarks an owner-relative rule, written as crn#tenant:<id>.user:* and rebound to the holder's own account when the access list is assembled — how a shared role says "your own account" without naming anyone.
namestringShort alphanumeric tenant identifier (slug)
Pattern: ^\w{4,16}$
allowedOriginsarrayoptionalList of origins permitted to make cross-origin requests to this tenant
Default: []
resourceIdentifierstringUnique Coldwave resource name (CRN) that identifies a resource
passwordSecretoptionalCustom secret used to pepper password hashes for this tenant
createdBystringResource identifier of the entity that created this resource

Errors

StatusDescriptionBody
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50

Read a tenant

The full entry, rootAccess included, which takes read on the tenant CRN itself and is deliberately rare. The part everyone inside the tenant may see is /tenant/{tenantId}/info; the pepper reference never appears in a response.

GET/api/v1/tenant/Yk3pL7rWq2

Path Parameters

NameDescription
tenantIdstringResource id: Base58 (9–10 characters) or a 16-character Crockford snowflake. Not an RFC 4122 UUID.
Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$

Response

NameDescription
enforce2FAbooleanoptionalWhether all users in this tenant are required to enrol in two-factor authentication
Default: true
rootAccessarrayAccess policies that apply at the root scope of this tenant
identifierThe resource this policy applies to
Alternative 1Resource identifier pattern (CRN), may include wildcards
Alternative 2Resource identifier pattern (CRN), may include wildcards
Alternative 3Resource identifier pattern (CRN), may include wildcards
Alternative 4Resource identifier pattern (CRN), may include wildcards
Alternative 5Resource identifier pattern (CRN), may include wildcards
Alternative 6Resource identifier pattern (CRN), may include wildcards
effectenumAccess policy effect — either allow or deny
Possible values: deny, allow
actionsarrayList of actions permitted by this policy
policyobjectoptionalAdditional constraints for this access policy
enforce2FAbooleanoptionalRequires the subject to have 2FA active before this access is granted
targetoptionalWhere a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Alternative 1Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Possible values: user, role, group
Alternative 2Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
isOwnerbooleanoptionalMarks an owner-relative rule, written as crn#tenant:<id>.user:* and rebound to the holder's own account when the access list is assembled — how a shared role says "your own account" without naming anyone.
namestringShort alphanumeric tenant identifier (slug)
Pattern: ^\w{4,16}$
allowedOriginsarrayoptionalList of origins permitted to make cross-origin requests to this tenant
Default: []
resourceIdentifierstringUnique Coldwave resource name (CRN) that identifies a resource
passwordSecretoptionalCustom secret used to pepper password hashes for this tenant
createdBystringResource identifier of the entity that created this resource

Errors

StatusDescriptionBody
403You do not have permission to perform this action
404The requested tenant could not be found
400The request did not match the schema for this endpoint. The details field carries the specific failures.error: Validation Error
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50

Read tenant info

The readable face of a tenant, without rootAccess and without the pepper reference. Each field is granted separately as crn#tenant:<id>.info$<field> and one the caller may not read is left out of the response rather than nulled; every user may read the name of their own tenant.

GET/api/v1/tenant/Yk3pL7rWq2/info

Path Parameters

NameDescription
tenantIdstringResource id: Base58 (9–10 characters) or a 16-character Crockford snowflake. Not an RFC 4122 UUID.
Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$

Response

NameDescription
resourceIdentifierstringUnique Coldwave resource name (CRN) that identifies a resource
namestringoptionalShort name of the tenant. Every user may read this for their own tenant; for any other it takes read on crn#tenant:<id>.info$name.
Pattern: ^\w{4,16}$
enforce2FAbooleanoptionalWhether the tenant makes every user present a second factor; present only for a caller holding read on crn#tenant:<id>.info$enforce2FA.
allowedOriginsarrayoptionalThe hosts — port included where it is not the default — whose browser origins may call this tenant; present only for a caller holding read on crn#tenant:<id>.info$allowedOrigins.

Errors

StatusDescriptionBody
403You do not have permission to perform this action
404The requested tenant could not be found
400The request did not match the schema for this endpoint. The details field carries the specific failures.error: Validation Error
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50

Delete a tenant

Removes the tenant entry and releases the origins it had registered for browser requests. The resources beneath it — users, roles, groups — are not deleted with it.

DELETE/api/v1/tenant/Yk3pL7rWq2

Path Parameters

NameDescription
tenantIdstringResource id: Base58 (9–10 characters) or a 16-character Crockford snowflake. Not an RFC 4122 UUID.
Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$

Errors

StatusDescriptionBody
403You do not have permission to perform this action
404The requested tenant could not be found
400The request did not match the schema for this endpoint. The details field carries the specific failures.error: Validation Error
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50

Update a tenant

Writes only the fields present in the body. allowedOrigins: [] really does clear the list and shuts every browser front-end out of the tenant, and rootAccess may not reach beyond crn#tenant:<id>.*.

PATCH/api/v1/tenant/Yk3pL7rWq2

Path Parameters

NameDescription
tenantIdstringResource id: Base58 (9–10 characters) or a 16-character Crockford snowflake. Not an RFC 4122 UUID.
Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$

Body

NameDescription
namestringoptionalNew short identifier for the tenant
Pattern: ^\w{4,16}$
passwordSecretoptionalCustom secret used to pepper password hashes for this tenant
rootAccessarrayoptionalAccess policies that apply at the root scope of this tenant
identifierThe resource this policy applies to
Alternative 1Resource identifier pattern (CRN), may include wildcards
Alternative 2Resource identifier pattern (CRN), may include wildcards
Alternative 3Resource identifier pattern (CRN), may include wildcards
Alternative 4Resource identifier pattern (CRN), may include wildcards
Alternative 5Resource identifier pattern (CRN), may include wildcards
Alternative 6Resource identifier pattern (CRN), may include wildcards
effectenumAccess policy effect — either allow or deny
Possible values: deny, allow
actionsarrayList of actions permitted by this policy
policyobjectoptionalAdditional constraints for this access policy
enforce2FAbooleanoptionalRequires the subject to have 2FA active before this access is granted
targetoptionalWhere a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Alternative 1Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Possible values: user, role, group
Alternative 2Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
isOwnerbooleanoptionalMarks an owner-relative rule, written as crn#tenant:<id>.user:* and rebound to the holder's own account when the access list is assembled — how a shared role says "your own account" without naming anyone.
enforce2FAbooleanoptionalWhether all users in this tenant are required to enrol in two-factor authentication
allowedOriginsarrayoptionalList of origins permitted to make cross-origin requests to this tenant

Errors

StatusDescriptionBody
403You do not have permission to perform this action
404The requested tenant could not be found
400The requested access permissions exceed what is allowed for this tenantcode: TENANT_NO_SUBSET_ERROR
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50

Replace a tenant

Overwrites the entry as a whole: an omitted enforce2FA or allowedOrigins falls back to its default rather than to what was stored. Only passwordSecret and createdBy survive the write, so the tenant does not lose its pepper.

PUT/api/v1/tenant/Yk3pL7rWq2

Path Parameters

NameDescription
tenantIdstringResource id: Base58 (9–10 characters) or a 16-character Crockford snowflake. Not an RFC 4122 UUID.
Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$

Body

NameDescription
enforce2FAbooleanoptionalWhether all users in this tenant are required to enrol in two-factor authentication
Default: true
allowedOriginsarrayoptionalList of origins permitted to make cross-origin requests to this tenant
Default: []
passwordSecretoptionalCustom secret used to pepper password hashes for this tenant
rootAccessarrayoptionalAccess policies that apply at the root scope of this tenant
identifierThe resource this policy applies to
Alternative 1Resource identifier pattern (CRN), may include wildcards
Alternative 2Resource identifier pattern (CRN), may include wildcards
Alternative 3Resource identifier pattern (CRN), may include wildcards
Alternative 4Resource identifier pattern (CRN), may include wildcards
Alternative 5Resource identifier pattern (CRN), may include wildcards
Alternative 6Resource identifier pattern (CRN), may include wildcards
effectenumAccess policy effect — either allow or deny
Possible values: deny, allow
actionsarrayList of actions permitted by this policy
policyobjectoptionalAdditional constraints for this access policy
enforce2FAbooleanoptionalRequires the subject to have 2FA active before this access is granted
targetoptionalWhere a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Alternative 1Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
Possible values: user, role, group
Alternative 2Where a device claimed under this rule lands: the kind of owner — user, role or group — or a CRN naming one outright. Only meaningful on a .pair rule.
isOwnerbooleanoptionalMarks an owner-relative rule, written as crn#tenant:<id>.user:* and rebound to the holder's own account when the access list is assembled — how a shared role says "your own account" without naming anyone.
namestringShort alphanumeric tenant identifier (slug)
Pattern: ^\w{4,16}$

Errors

StatusDescriptionBody
403You do not have permission to perform this action
404The requested tenant could not be found
400The requested access permissions exceed what is allowed for this tenantcode: TENANT_NO_SUBSET_ERROR
401No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key.error: string
500The request failed for a reason that is not the caller's to fix. Safe to retry.error: string, message: string, statusCode: 50