BetterIAM
Server API

groups

Groups let you grant access to many people at once.

Groups let you grant access to many people at once. Instead of binding the same roles to every member of the finance team, you bind them once to a "Finance" group and manage who is in it; everyone in the group receives every role bound to it, and leaving the group removes that access immediately. Memberships can be temporary, which suits contractors, on-call rotations, and project teams.

How group access works

A group has no permissions of its own. Access comes from role bindings whose subject is the group, so changing membership is, in effect, granting or revoking those roles. That is why adding or removing a member requires authority over each of the group's bindings, not just permission to edit the group: someone who could not grant a role directly cannot grant it by putting a person in a group.

Temporary memberships carry an expiresAt (epoch milliseconds). They stop counting the moment they lapse, are left out of listMembers, and are removed later by the purge job. Memberships created by an access package are tagged with the package's assignment; editing one by hand takes it over, so revoking the package no longer removes it.

Methods10
Serveriam.api.groups
Clientclient.groups
HTTPPOST /api/iam/groups/*
MethodWhat it doesAccess
addMemberAdds a person to a group so they receive every role bound to the group, optionally until a given time.Credential
addMembersAdds up to 100 people to a group in one transaction, all with the same optional expiry.Credential
createCreates a group in the tenant.Credential
deleteDeletes a group together with its memberships, its role bindings, their activations, and its relationship tuples.Credential
getReturns one group by id.Credential
listLists every group in the tenant.Credential
listMembersLists the current members of a group, with membershipExpiresAt on temporary memberships.Credential
removeMemberRemoves a person from a group, ending the access the group's roles gave them.Credential
updateRenames a group or changes its description.Credential
updateMemberExtends, shortens, or clears the expiry of an existing membership.Credential

addMember

Adds a person to a group so they receive every role bound to the group, optionally until a given time.

POST/api/iam/groups/addMember
client.groups.addMember()Credential

Used inTemporary access,Access lifecycle,Sharing and access questions

  • Permission: iam:groups:update on the group, plus grant authority for each of the group's role bindings.
  • Audited as: iam:groups:update.
  • Errors: CONFLICT when the person is already a live member; NOT_FOUND when the group or person is not in this tenant; ACCESS_DENIED without authority over one of the group's bindings; SOD_CONFLICT when the membership would give the person a combination of roles a separation-of-duties rule forbids.

Pass expiresAt to make the membership temporary. Adding someone whose earlier membership has lapsed renews it instead of failing, and the renewed membership no longer belongs to the access package that originally created it.

// Give a contractor the team's access for 30 days.
await iam.api.groups.addMember(credential, {
  tenantId,
  groupId,
  identityId,
  expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,
});
Input

Prop

Type

Returns

A GroupMember 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/groups/addMember" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>",
  "identityId": "<identityId>"
}'
Signature
iam.api.groups.addMember(
  credential: CredentialInput,
  input: { tenantId: string; groupId: string; identityId: string; expiresAt?: number },
): Promise<GroupMember>

addMembers

Adds up to 100 people to a group in one transaction, all with the same optional expiry.

POST/api/iam/groups/addMembers
client.groups.addMembers()Credential
  • Permission: iam:groups:update on the group, plus grant authority for each of the group's role bindings.
  • Audited as: iam:groups:update.
  • Errors: INVALID_INPUT when identityIds is empty; any error addMember can raise for one person (including SOD_CONFLICT) rejects the whole batch.

Use it for cohort onboarding, such as a new class of employees or everyone joining a project on the same day. Duplicate ids are ignored. Because it is atomic, either everyone is added or no one is.

Input

Prop

Type

Returns

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/groups/addMembers" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>",
  "identityIds": [
    "<identityId>"
  ]
}'
Signature
iam.api.groups.addMembers(
  credential: CredentialInput,
  input: {
    tenantId: string;
    groupId: string;
    identityIds: string[];
    expiresAt?: number;
  },
): Promise<{ members: GroupMember[] }>

create

Creates a group in the tenant.

POST/api/iam/groups/create
client.groups.create()Credential
  • Permission: iam:groups:create on the tenant.
  • Audited as: iam:groups:create.
  • Errors: LIMIT_EXCEEDED when the tenant's plan limit for groups is reached; INVALID_INPUT for an empty name or a description over 512 characters.

A new group is empty and grants nothing until you bind roles to it with bindings.create and add members.

Input

A GroupInput object:

Prop

Type

Returns

A Group 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/groups/create" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "name": "<name>"
}'
Signature
iam.api.groups.create(
  credential: CredentialInput,
  input: GroupInput,
): Promise<Group>

delete

Deletes a group together with its memberships, its role bindings, their activations, and its relationship tuples.

POST/api/iam/groups/delete
client.groups.delete()Credential
  • Permission: iam:groups:delete on the group, plus grant authority for each of its role bindings.
  • Audited as: iam:groups:delete.
  • Errors: RESOURCE_IN_USE (409) when an access package still grants the group or names it in an automatic assignment rule, or when the group approves package requests or eligible-binding activations.

The in-use checks exist so deleting a group never silently changes who can approve requests or what a package grants: point those at another group first.

Input

Prop

Type

Returns

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/groups/delete" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>"
}'
Signature
iam.api.groups.delete(
  credential: CredentialInput,
  input: { tenantId: string; groupId: string },
): Promise<{ deleted: boolean }>

get

Returns one group by id.

POST/api/iam/groups/get
client.groups.get()Credential
  • Permission: iam:groups:read on the group.
  • Audited as: iam:groups:read.
  • Errors: NOT_FOUND when the group is not in this tenant.
Input

Prop

Type

Returns

A Group 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/groups/get" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>"
}'
Signature
iam.api.groups.get(
  credential: CredentialInput,
  input: { tenantId: string; groupId: string },
): Promise<Group>

list

Lists every group in the tenant.

POST/api/iam/groups/list
client.groups.list()Credential
  • Permission: iam:groups:read on the tenant.
  • Audited as: iam:groups:read.
Input

Prop

Type

Returns

An array of Group.

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/groups/list" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>"
}'
Signature
iam.api.groups.list(
  credential: CredentialInput,
  input: { tenantId: string },
): Promise<Group[]>

listMembers

Lists the current members of a group, with membershipExpiresAt on temporary memberships.

POST/api/iam/groups/listMembers
client.groups.listMembers()Credential
  • Permission: iam:groups:read on the group.
  • Audited as: iam:groups:read.
  • Errors: NOT_FOUND when the group is not in this tenant.

Lapsed memberships are left out even before the purge job removes them, so the list always matches who currently receives the group's roles. Members are returned as public identities, without credential material.

Input

Prop

Type

Returns

An array of PublicIdentity & 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/groups/listMembers" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>"
}'
Signature
iam.api.groups.listMembers(
  credential: CredentialInput,
  input: { tenantId: string; groupId: string },
): Promise<(PublicIdentity & { membershipExpiresAt?: number })[]>

removeMember

Removes a person from a group, ending the access the group's roles gave them.

POST/api/iam/groups/removeMember
client.groups.removeMember()Credential
  • Permission: iam:groups:update on the group, plus grant authority for each of the group's role bindings.
  • Audited as: iam:groups:update.

Any just-in-time activations the person had of the group's eligible bindings end at the same time, so removing someone from a group cannot leave them elevated. Removing a person who is not a member succeeds and changes nothing.

Input

Prop

Type

Returns

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/groups/removeMember" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>",
  "identityId": "<identityId>"
}'
Signature
iam.api.groups.removeMember(
  credential: CredentialInput,
  input: { tenantId: string; groupId: string; identityId: string },
): Promise<{ deleted: boolean }>

update

Renames a group or changes its description.

POST/api/iam/groups/update
client.groups.update()Credential
  • Permission: iam:groups:update on the group.
  • Audited as: iam:groups:update.
  • Errors: INVALID_INPUT when neither name nor description is given.
Input

Prop

Type

Returns

A Group 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/groups/update" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>"
}'
Signature
iam.api.groups.update(
  credential: CredentialInput,
  input: { tenantId: string; groupId: string; name?: string; description?: string },
): Promise<Group>

updateMember

Extends, shortens, or clears the expiry of an existing membership.

POST/api/iam/groups/updateMember
client.groups.updateMember()Credential
  • Permission: iam:groups:update on the group, plus grant authority for each of the group's role bindings.
  • Audited as: iam:groups:update.
  • Errors: NOT_FOUND when the person is not a live member of the group.

Pass expiresAt: null to make a temporary membership permanent. Editing a membership that an access package created takes it over: revoking the package will no longer remove it.

Input

Prop

Type

Returns

A GroupMember 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/groups/updateMember" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "groupId": "<groupId>",
  "identityId": "<identityId>",
  "expiresAt": 1790000000000
}'
Signature
iam.api.groups.updateMember(
  credential: CredentialInput,
  input: {
    tenantId: string;
    groupId: string;
    identityId: string;
    expiresAt: number | null;
  },
): Promise<GroupMember>

Was this page helpful?

Better IAM is created by Sean Filimon

Last updated

On this page