roles
Roles are named sets of permissions for a job function, such as Editor or Approver, that bindings give to people and groups.
Roles are named sets of permissions for a job function, such as Editor or Approver, that bindings give to people
and groups. You define what an editor may do once, bind the role to everyone
who edits, and change it in one place when the job changes: every holder sees the change at their next request. A
role can build on other roles through inheritance, and it can also be taken on temporarily through a trust with
assume instead of a binding. The guide is roles and bindings.
How a role grants
A role grants the union of three sources:
- Its own permissions. Either a
permissionslist, which becomes one inline allow statement (RolePermissions) over every resource of the tenant, or a full inlinedocumentwhen access depends on conditions or specific resources. You pass one or the other, not both. - Attached policies.
policyIdsnames stored, versioned policies that several roles can share. - Inherited roles.
inheritslists up to 20 roles whose grants this role includes, recursively. A role cannot inherit itself, form a cycle, or inherit a protected role.
Every role also records the grant authority it was created under. That authority's ceiling bounds everything the role grants, whoever binds it, and inherited grants are bounded by the inheriting role's ceilings as well as their own, so inheriting a broader role never widens a delegated administrator's reach. Only the holder of that authority, or root, may edit or delete the role.
The protected Owner role, created with every tenant, cannot be updated, deleted, inherited, or bound through this
API; ownership changes go through identities.setOwner.
| Method | What it does | Access |
|---|---|---|
assume | Exchanges your session for a short-lived role session in a target tenant, through a trust the platform root created. | Credential |
create | Creates a role from a permissions list, an inline policy document, attached policies, inherited roles, or a mix of them. | Credential |
delete | Deletes a role together with its bindings and their activations. | Credential |
get | Returns one role by id, with its attached policies, inline document, and inherited roles. | Credential |
list | Lists every role in the tenant, including the protected Owner role. | Credential |
listBindings | Lists who holds a role: its bindings, each with a summary of the person, service account, or group it names. | Credential |
listSessions | Lists the live role sessions in the tenant, of one role or trust when given, newest first. | Credential |
revokeSessions | Ends every role session of a role issued before a point in time, whichever trust or provider issued it. | Credential |
update | Changes a role's name, description, permissions or inline document, attached policies, or inherited roles. | Credential |
assume
Exchanges your session for a short-lived role session in a target tenant, through a trust the platform root created.
Used inAdvanced,Sign-in methods,Temporary access
- Permission:
iam:roles:assumeon the target role (iam/{roleId}), evaluated in your own tenant, and a trust that names you as its source identity. - Audited as:
iam:roles:assumein your own tenant, androle:assumedin the target tenant (with the trust, your tenant, the duration, the credential format, and the names of any session tags), so both sides can see it. - Errors:
ROLE_CHAINING_DISABLEDwhen you call it from a role session;IMPERSONATION_RESTRICTEDfrom a "view as" session;NOT_FOUNDwhen the trust is not in the target tenant;ACCESS_DENIEDwhen the trust is revoked, names another source identity, requires MFA your session lacks, expects an external ID you did not match, or does not admit the session tags or source identity you passed;TENANT_INACTIVEwhen the target tenant or an ancestor is not active;INVALID_INPUTfor adurationSecondsoutside the allowed range or a malformed session name, source identity, tag, or audience;FEATURE_DISABLEDforformat: 'jwt'when the deployment has nosts.jwtsigning keys;INVALID_POLICYorINVALID_ACTIONfor an invalid sessionpolicy.
Use it for cross-tenant support or automation, or for one task that needs a role nobody should hold permanently.
The platform root sets up each trust with trust.create: exactly one source
identity, one target role, and optionally MFA, an external ID, and a ceiling. The returned token is a credential
for the target tenant whose permissions are exactly the role's, bounded by the trust's ceiling and by the optional
session policy, which can only narrow them. Your own roles do not carry over, and neither do the limits of the
credential you called with: an API key's scopes or a session token's policy only decide whether you may assume the
role (checked again on every use), not what the role session may do. Your MFA state and sign-in time do carry over,
and the address you called from is recorded so the target tenant's IP allowlist and network blocks apply to the
role session too.
The session lasts durationSeconds: 900 by default, at most the smaller of the deployment's
sts.maxRoleSessionSeconds (3600 unless configured) and the trust's own limit, and never longer than the session
you called from. A value outside that range is refused rather than shortened. A role session cannot assume another
role.
Optional inputs describe the session for policies and the audit log: sessionName (who or what is acting, such as
a ticket number), sourceIdentity (the person behind an automated caller), and tags (key/value pairs that
policies read as principal.sessionTags.{key}). A trust admits no tags and forbids a source identity unless it is
configured to allow them, because both can satisfy policy conditions. format: 'jwt' issues the credential as a
signed JWT for audience instead of an opaque token.
const { token, session } = await iam.api.roles.assume(credential, {
tenantId: customerTenantId,
trustId,
durationSeconds: 900,
policy: {
version: 1,
statements: [{ effect: 'allow', actions: ['documents:read'], resources: ['*'] }],
},
});
// Call the API as { token } in customerTenantId until session.expiresAt.A AssumeRoleInput object:
Prop
Type
A RoleCredential object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/assume" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"trustId": "<trustId>"
}'iam.api.roles.assume(
credential: CredentialInput,
input: AssumeRoleInput,
): Promise<RoleCredential>create
Creates a role from a permissions list, an inline policy document, attached policies, inherited roles, or a mix of them.
Used inQuickstart,Relationships,Roles and bindings,Just-in-time elevation,Privileged access,Access lifecycleand 1 more
- Permission:
iam:roles:createon the tenant, plus an active grant authority. - Audited as:
iam:roles:create. - Errors:
INVALID_INPUTwhen bothpermissionsanddocumentare given,permissionsis empty, more than 20 roles are inherited, or the name or description (at most 512 characters) is invalid;INVALID_POLICY,INVALID_ACTION, orINVALID_RESOURCE_TYPEwhen the permissions or document do not validate against the catalog;NOT_FOUNDwhen an attached policy or inherited role is not in this tenant;PROTECTED_RESOURCEwhen inheriting a protected role;GRANT_AUTHORITY_REQUIREDwhen you hold no active grant authority;LIMIT_EXCEEDEDwhen the tenant's plan limit for roles is reached.
A new role grants nothing until it is bound. Create one role per job function in your product rather than one per person.
const editor = await iam.api.roles.create(credential, {
tenantId,
name: 'Editor',
description: 'Reads and writes documents',
permissions: ['documents:read', 'documents:write'],
});
// A manager does everything an editor does, plus exports.
const manager = await iam.api.roles.create(credential, {
tenantId,
name: 'Manager',
permissions: ['reports:export'],
inherits: [editor.id],
});A RoleInput object:
Prop
Type
A Role object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/create" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"name": "<name>"
}'iam.api.roles.create(
credential: CredentialInput,
input: RoleInput,
): Promise<Role>delete
Deletes a role together with its bindings and their activations.
- Permission:
iam:roles:deleteon the role, and the grant authority the role was created under (or root). - Audited as:
iam:roles:delete. - Errors:
RESOURCE_IN_USE(409) while another role inherits it or an access package includes it;PROTECTED_RESOURCEfor a protected role;ACCESS_DENIEDwhen another administrator's authority created the role;NOT_FOUND;INVARIANT_VIOLATION.
Everyone who held the role loses it at once. The in-use checks exist so that deleting a role never silently changes what another role or a package grants: change those first.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/delete" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"roleId": "<roleId>"
}'iam.api.roles.delete(
credential: CredentialInput,
input: { tenantId: string; roleId: string },
): Promise<{ deleted: boolean }>get
Returns one role by id, with its attached policies, inline document, and inherited roles.
- Permission:
iam:roles:readon the role. - Audited as:
iam:roles:read. - Errors:
NOT_FOUNDwhen the role is not in this tenant.
Prop
Type
A Role object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/get" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"roleId": "<roleId>"
}'iam.api.roles.get(
credential: CredentialInput,
input: { tenantId: string; roleId: string },
): Promise<Role>list
Lists every role in the tenant, including the protected Owner role.
- Permission:
iam:roles:readon the tenant. - Audited as:
iam:roles:read.
Prop
Type
An array of Role.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/list" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.roles.list(
credential: CredentialInput,
input: { tenantId: string },
): Promise<Role[]>listBindings
Lists who holds a role: its bindings, each with a summary of the person, service account, or group it names.
- Permission:
iam:bindings:readon the role. - Audited as:
iam:bindings:read. - Errors:
NOT_FOUNDwhen the role is not in this tenant.
Expired bindings are left out. Future-dated and eligible bindings are included, so check startsAt and eligible
to tell who holds the role right now. Each entry has subject (id, name, email, and kind for an identity; id and
name for a group). Group bindings are listed as the group, not expanded to members, and holders of roles that
inherit this one are not included.
Prop
Type
An array of Binding & object.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/listBindings" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"roleId": "<roleId>"
}'iam.api.roles.listBindings(
credential: CredentialInput,
input: { tenantId: string; roleId: string },
): Promise<(Binding & { subject?: BindingSubject })[]>listSessions
Lists the live role sessions in the tenant, of one role or trust when given, newest first.
- Permission:
iam:trust:readon the role (iam/{roleId}), or on the tenant withoutroleId. - Audited as:
iam:trust:read. - Errors:
NOT_FOUNDwhenroleIdis not a role of this tenant;INVALID_INPUTfor alimitoutside 1 to 500.
Each entry is a summary built for the target tenant's administrators: the session id, role, trust, the identity it
acts as, the source tenant, session name, source identity, the web identity's provider and subject, MFA, format,
creation and expiry times, and the recorded client address. Tokens, hashes, policies, and authority ids are never
included. Expired sessions, sessions under a revoked trust, and sessions already below a revocation watermark are
left out. limit defaults to 100. Use it to see who is currently working in the tenant through a trust before
revoking with revokeSessions.
Prop
Type
An array of RoleSessionSummary.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/listSessions" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.roles.listSessions(
credential: CredentialInput,
input: { tenantId: string; roleId?: string; trustId?: string; limit?: number },
): Promise<RoleSessionSummary[]>revokeSessions
Ends every role session of a role issued before a point in time, whichever trust or provider issued it.
- Permission:
iam:roles:revoke-sessionson the role, with recent authentication. - Audited as:
iam:roles:revoke-sessionsandrole:sessions-revoked(with the watermark and the number of sessions deleted). - Errors:
INVALID_INPUTwhenbeforeis not a whole number of milliseconds, is negative, or lies in the future;NOT_FOUNDwhen the role is not in this tenant;RECENT_AUTH_REQUIRED;ACCESS_DENIED.
This is the "revoke older sessions" lever for an incident: before defaults to now, which ends every role session
issued so far, while new assumptions keep working. The role's sessionsRevokedBefore watermark only moves forward
and is kept by update and configuration sync, so a session created before it is refused at its next use
(with UNAUTHENTICATED), and matching rows are deleted at once. It only removes access, so it can be delegated to
the target tenant's administrators. Session JWTs that other services verify offline stay valid there until they
expire. To end the sessions of one trust or one OIDC provider instead, use
trust.revokeSessions or
oidcProviders.revokeSessions.
const { revoked, sessionsRevokedBefore } = await iam.api.roles.revokeSessions(credential, { tenantId, roleId });Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/revokeSessions" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"roleId": "<roleId>"
}'iam.api.roles.revokeSessions(
credential: CredentialInput,
input: { tenantId: string; roleId: string; before?: number },
): Promise<{ roleId: string; sessionsRevokedBefore: number; revoked: number }>update
Changes a role's name, description, permissions or inline document, attached policies, or inherited roles.
Used inRoles and bindings
- Permission:
iam:roles:updateon the role, and the grant authority the role was created under (or root). - Audited as:
iam:roles:update. - Errors:
PROTECTED_RESOURCEfor a protected role, or when inheriting one;ACCESS_DENIEDwhen another administrator's authority created the role;GRANT_AUTHORITY_REQUIREDwhen you hold no active grant authority;INVALID_INPUTwhen bothpermissionsanddocumentare given or the inheritance would form a cycle;INVALID_POLICY,INVALID_ACTION, orINVALID_RESOURCE_TYPE;NOT_FOUND;INVARIANT_VIOLATIONwhen the change would newly break an enforced access invariant.
Only the fields you pass change. permissions replaces the inline document with a new permissions statement,
document: null removes the inline document, policyIds replaces the attached set, and inherits: [] clears
inheritance. Everyone who holds the role, directly, through a group, or through a role that inherits it, sees the
change at their next request, so preview it first with impact.preview.
await iam.api.roles.update(credential, {
tenantId,
roleId: editor.id,
permissions: ['documents:read', 'documents:write', 'documents:share'],
});A RoleUpdate object:
Prop
Type
A Role object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/roles/update" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"roleId": "<roleId>"
}'iam.api.roles.update(
credential: CredentialInput,
input: RoleUpdate,
): Promise<Role>Better IAM is created by Sean Filimon
Last updated