Appearance
IAM — Roles
A role is a named bundle of access rules — CRN patterns with the actions they allow or deny — held by every account paired to it, and capped by the tenant's rootAccess. Effective access is assembled per request from the rules on the account plus every role it holds, directly or through a user group — so a change lands on the holders' next request, with no new token.
The ceiling itself is set on the tenant; user groups hand out several roles at once, and require2FA forces the holders through the second-factor flow in authentication. Pairing and rule changes are published as IAM_ROLE_PAIR_USER and IAM_ROLE_UPDATE.
| POST | Create a role/api/v1/role |
| GET | List roles/api/v1/role |
| GET | Read a role/api/v1/role/:roleId |
| DELETE | Delete a role/api/v1/role/:roleId |
| PATCH | Update a role/api/v1/role/:roleId |
| PUT | Replace a role/api/v1/role/:roleId |
| POST | Add users to a role/api/v1/role/:roleId/user |
| GET | List role holders/api/v1/role/:roleId/user |
| DELETE | Remove users from a role/api/v1/role/:roleId/user |
Create a role
The role's access is checked against the tenant's rootAccess, and a rule reaching beyond it is refused with both sets in the error. tenantId is only needed when the caller's own access spans more than one tenant.
POST
/api/v1/roleBody
| Name | Description |
|---|---|
namestring | Display name for the role min length 1 · max length 64 |
descriptionstringoptional | Optional description of the role's purpose |
accessarrayoptional | Access policies assigned to members of this role Default: [] |
| identifier | The resource this policy applies to |
| Alternative 1 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 2 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 3 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 4 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 5 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 6 | Resource identifier pattern (CRN), may include wildcards |
effectenum | Access policy effect — either allow or deny Possible values: deny, allow |
actionsarray | List of actions permitted by this policy |
policyobjectoptional | Additional constraints for this access policy |
enforce2FAbooleanoptional | Requires the subject to have 2FA active before this access is granted |
targetoptional | Where 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 1 | Where 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 2 | Where 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. |
isOwnerbooleanoptional | Marks 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. |
require2FAbooleanoptional | Whether members of this role must have two-factor authentication enabled Default: false |
tenantIdstringoptional | Tenant to create this role in — defaults to the authenticated user's tenant Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$ |
Response
| Name | Description |
|---|---|
resourceIdentifierstring | Unique Coldwave resource name (CRN) that identifies a resource |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
400 | The requested role permissions exceed what is allowed for this tenant | code: ROLE_NO_SUBSET_ERROR |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
List roles
The roles of the caller's tenant; it takes read on crn#tenant:<id>.role:*, not on each role. A caller whose access spans several tenants gets a conflict instead — narrow the request with X-Tenant-Id.
GET
/api/v1/roleResponse
| Name | Description |
|---|---|
namestring | Display name of the role min length 1 · max length 64 |
descriptionstringoptional | Human-readable description of the role's purpose |
accessarrayoptional | Access policies assigned to members of this role Default: [] |
| identifier | The resource this policy applies to |
| Alternative 1 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 2 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 3 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 4 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 5 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 6 | Resource identifier pattern (CRN), may include wildcards |
effectenum | Access policy effect — either allow or deny Possible values: deny, allow |
actionsarray | List of actions permitted by this policy |
policyobjectoptional | Additional constraints for this access policy |
enforce2FAbooleanoptional | Requires the subject to have 2FA active before this access is granted |
targetoptional | Where 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 1 | Where 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 2 | Where 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. |
isOwnerbooleanoptional | Marks 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. |
require2FAbooleanoptional | Whether members of this role must have two-factor authentication enabled Default: false |
resourceIdentifierstring | Unique Coldwave resource name (CRN) that identifies a resource |
createdBystring | Resource identifier of the entity that created this resource |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
Read a role
The role with the access rules it grants. Who holds it is a separate call, GET /role/{roleId}/user.
GET
/api/v1/role/Yk3pL7rWq2Path Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Name | Description |
|---|---|
namestring | Display name of the role min length 1 · max length 64 |
descriptionstringoptional | Human-readable description of the role's purpose |
accessarrayoptional | Access policies assigned to members of this role Default: [] |
| identifier | The resource this policy applies to |
| Alternative 1 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 2 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 3 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 4 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 5 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 6 | Resource identifier pattern (CRN), may include wildcards |
effectenum | Access policy effect — either allow or deny Possible values: deny, allow |
actionsarray | List of actions permitted by this policy |
policyobjectoptional | Additional constraints for this access policy |
enforce2FAbooleanoptional | Requires the subject to have 2FA active before this access is granted |
targetoptional | Where 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 1 | Where 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 2 | Where 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. |
isOwnerbooleanoptional | Marks 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. |
require2FAbooleanoptional | Whether members of this role must have two-factor authentication enabled Default: false |
resourceIdentifierstring | Unique Coldwave resource name (CRN) that identifies a resource |
createdBystring | Resource identifier of the entity that created this resource |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
400 | The request did not match the schema for this endpoint. The details field carries the specific failures. | error: Validation Error |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
Delete a role
Unpairs every user holding the role before removing it, so all of them lose the access it granted at that moment. The accounts themselves are untouched.
DELETE
/api/v1/role/Yk3pL7rWq2Path Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
400 | The request did not match the schema for this endpoint. The details field carries the specific failures. | error: Validation Error |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
Update a role
Writes only the fields present. access replaces the rule set as a whole rather than merging into it and is still capped by the tenant's rootAccess — leave it out to keep the rules as they are.
PATCH
/api/v1/role/Yk3pL7rWq2Path Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Name | Description |
|---|---|
namestringoptional | New display name for the role min length 1 · max length 64 |
descriptionstringoptional | Updated description of the role's purpose |
accessarrayoptional | Replacement access policies for this role — replaces the existing set |
| identifier | The resource this policy applies to |
| Alternative 1 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 2 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 3 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 4 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 5 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 6 | Resource identifier pattern (CRN), may include wildcards |
effectenum | Access policy effect — either allow or deny Possible values: deny, allow |
actionsarray | List of actions permitted by this policy |
policyobjectoptional | Additional constraints for this access policy |
enforce2FAbooleanoptional | Requires the subject to have 2FA active before this access is granted |
targetoptional | Where 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 1 | Where 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 2 | Where 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. |
isOwnerbooleanoptional | Marks 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. |
require2FAbooleanoptional | Whether members of this role must have two-factor authentication enabled |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
400 | The requested role permissions exceed what is allowed for this tenant | code: ROLE_NO_SUBSET_ERROR |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
Replace a role
Overwrites the whole role: an omitted access leaves it with no rules at all and an omitted require2FA falls back to false. Only the original createdBy survives the write.
PUT
/api/v1/role/Yk3pL7rWq2Path Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Name | Description |
|---|---|
namestring | Display name for the role min length 1 · max length 64 |
descriptionstringoptional | Optional description of the role's purpose |
accessarrayoptional | Access policies assigned to members of this role Default: [] |
| identifier | The resource this policy applies to |
| Alternative 1 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 2 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 3 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 4 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 5 | Resource identifier pattern (CRN), may include wildcards |
| Alternative 6 | Resource identifier pattern (CRN), may include wildcards |
effectenum | Access policy effect — either allow or deny Possible values: deny, allow |
actionsarray | List of actions permitted by this policy |
policyobjectoptional | Additional constraints for this access policy |
enforce2FAbooleanoptional | Requires the subject to have 2FA active before this access is granted |
targetoptional | Where 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 1 | Where 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 2 | Where 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. |
isOwnerbooleanoptional | Marks 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. |
require2FAbooleanoptional | Whether members of this role must have two-factor authentication enabled Default: false |
tenantIdstringoptional | Tenant to create this role in — defaults to the authenticated user's tenant Pattern: ^[0-9A-HJ-NP-Za-km-z]{9,16}$ |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
400 | The requested role permissions exceed what is allowed for this tenant | code: ROLE_NO_SUBSET_ERROR |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
Add users to a role
Takes share on the role and read on every account named — handing a role out is acting on the account that receives it. user is one CRN or a list, each inside the caller's own tenant; a user who already holds the role is left unchanged.
POST
/api/v1/role/Yk3pL7rWq2/userPath Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Name | Description |
|---|---|
| user | One or more user resource identifiers to assign to this role |
Alternative 1string | Unique Coldwave resource name (CRN) that identifies a resource |
Alternative 2array | One or more user resource identifiers to assign to this role |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
400 | The request did not match the schema for this endpoint. The details field carries the specific failures. | error: Validation Error |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
List role holders
The CRNs of the users paired to the role. It takes read on the role itself, not on each account it returns.
GET
/api/v1/role/Yk3pL7rWq2/userPath Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Name | Description |
|---|
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
400 | The request did not match the schema for this endpoint. The details field carries the specific failures. | error: Validation Error |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |
Remove users from a role
The same privilege as handing the role out: share on the role and read on every account named. Removing someone who never held it is a no-op, not a conflict.
DELETE
/api/v1/role/Yk3pL7rWq2/userPath Parameters
| Name | Description |
|---|---|
roleIdstring | Resource 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
| Name | Description |
|---|---|
| user | One or more user resource identifiers to assign to this role |
Alternative 1string | Unique Coldwave resource name (CRN) that identifies a resource |
Alternative 2array | One or more user resource identifiers to assign to this role |
Errors
| Status | Description | Body |
|---|---|---|
403 | You do not have permission to perform this action | |
404 | The requested role could not be found | |
409 | A tenant with the given name already exists | code: IAM_TENANT_CONFLICT_ERROR |
400 | The request did not match the schema for this endpoint. The details field carries the specific failures. | error: Validation Error |
401 | No valid access token was presented, or the DPoP proof accompanying it was missing, expired or bound to a different key. | error: string |
500 | The request failed for a reason that is not the caller's to fix. Safe to retry. | error: string, message: string, statusCode: 50 |