BetterIAM
Server API

resources

This group registers the resources your product protects, so authorization can decide about them without calling back into your application.

This group registers the resources your product protects, so authorization can decide about them without calling back into your application. A registration records a resource's typed attributes, its owner, and its parent, and policies read them as resource.* context keys. Registered resources can also be listed by what the caller may do with them (iam.listAccessible), which is what makes filtered list pages possible.

Managed and application-owned resources

Every resource type is one of two kinds (see managed types):

  • Application-owned types are resolved by your application at decision time through the resolveResource option. Your database stays the source of truth and nothing is registered here.
  • Managed types (declared with managed: true, and every tenant-defined type) are registered through this group. Authorization reads the registration, so no callback is involved, and listAccessible can enumerate them.

This group only accepts managed types; an application-owned or unknown type fails with INVALID_RESOURCE_TYPE. A registration is addressed by type and id (your identifier, at most 128 characters). The returned record keeps your identifier in resourceId; its id field is an internal record id.

During evaluation a registered resource exposes its attributes as resource.{name}, plus resource.ownerId, resource.parentId, and resource.parentType when set, and the caller's relations on it and on its parent. Administrative calls on iam/{type}/{id} see the same keys, so a policy can let owners manage their own resources:

{
  effect: 'allow',
  actions: ['iam:resources:update', 'iam:resources:delete'],
  resources: ['iam/project/*'],
  conditions: { StringEquals: { 'resource.ownerId': '${principal.id}' } },
}

Attribute values must match the type's declared schema: only declared names, with the declared type (string, number, or boolean); strings are at most 2048 characters with no control characters.

Methods6
Serveriam.api.resources
Clientclient.resources
HTTPPOST /api/iam/resources/*
MethodWhat it doesAccess
deleteRemoves a registered resource and every relationship tuple on it.Credential
getReturns the registration of one resource.Credential
listLists registered resources, optionally of one type, under one parent, or owned by one identity.Credential
registerRegisters a managed resource with its attributes, owner, and parent.Credential
registerManyRegisters up to 100 managed resources in one transaction, either all of them or none.Credential
updateReplaces a registered resource's attributes, or changes or clears its owner.Credential

delete

Removes a registered resource and every relationship tuple on it.

POST/api/iam/resources/delete
client.resources.delete()Credential
  • Permission: iam:resources:delete on iam/{type}/{id}.
  • Audited as: iam:resources:delete, on {type}/{id}.
  • Errors: NOT_FOUND when the resource is not registered; RESOURCE_IN_USE when registered child resources still point at it; INVARIANT_VIOLATION when an enforced access invariant would newly fail.

Delete children first: a parent cannot be removed while resources registered under it exist. Once deleted, any decision about the resource sees no attributes, owner, or relations.

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

get

Returns the registration of one resource.

POST/api/iam/resources/get
client.resources.get()Credential
  • Permission: iam:resources:read on iam/{type}/{id}.
  • Audited as: iam:resources:read, on {type}/{id}.
  • Errors: NOT_FOUND when the resource is not registered.
Input

Prop

Type

Returns

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

list

Lists registered resources, optionally of one type, under one parent, or owned by one identity.

POST/api/iam/resources/list
client.resources.list()Credential
  • Permission: iam:resources:read on iam/{type}/* when type is given, otherwise on iam/*.
  • Audited as: iam:resources:read.
  • Errors: INVALID_INPUT when limit is outside 1 to 1000.

Results are sorted by type/id, so pages are stable and meaningful; limit defaults to 100, with offset for the next page. parentId is the parent's own identifier. This is an administrative listing of what exists. To list what a person may act on, use listAccessible.

Input

Prop

Type

Returns

An array of ResourceRecord.

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/resources/list" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>"
}'
Signature
iam.api.resources.list(
  credential: CredentialInput,
  input: {
    tenantId: string;
    type?: string;
    parentId?: string;
    ownerId?: string;
    limit?: number;
    offset?: number;
  },
): Promise<ResourceRecord[]>

register

Registers a managed resource with its attributes, owner, and parent.

POST/api/iam/resources/register
client.resources.register()Credential

Used inPermission catalog,Resources and catalog

  • Permission: iam:resources:create on iam/{type}/{id}.
  • Audited as: iam:resources:create, on {type}/{id}.
  • Errors: INVALID_RESOURCE_TYPE when the type is unknown or application-owned; CONFLICT when the resource is already registered; INVALID_INPUT for undeclared or wrongly typed attributes, a missing parentId on a type that declares a parent, or a parentId on a type that does not; NOT_FOUND when the parent is not registered or ownerId is not an identity of the tenant (or was deleted); LIMIT_EXCEEDED at the tenant's resource limit.

Because the permission is checked on the resource's own address, policies can limit who registers what, for example iam/project/* for project administrators. Register a resource when your product creates it, in the same request, so access rules apply from the first moment. The parent cannot be changed later.

await iam.api.resources.register(credential, {
  tenantId,
  type: 'task',
  id: 'task_812',
  parentId: 'proj_apollo', // a registered `project`, because `task` declares `parent: 'project'`
  ownerId: identityId,
  attributes: { priority: 2 }, // the type declares `priority: 'number'`
});
Input

Prop

Type

Returns

A ResourceRecord 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/resources/register" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "type": "<type>",
  "id": "<id>"
}'
Signature
iam.api.resources.register(
  credential: CredentialInput,
  input: {
    tenantId: string;
    type: string;
    id: string;
    attributes?: Record<string, Json>;
    parentId?: string;
    ownerId?: string;
  },
): Promise<ResourceRecord>

registerMany

Registers up to 100 managed resources in one transaction, either all of them or none.

POST/api/iam/resources/registerMany
client.resources.registerMany()Credential

Used inBatches and reverse queries

  • Permission: iam:resources:create on iam/{type}/{id} for every item.
  • Audited as: iam:resources:create, once per item.
  • Errors: INVALID_INPUT for an empty list or more than 100 items; ACCESS_DENIED naming the first item the caller may not register (only that denial is recorded and nothing is written); LIMIT_EXCEEDED when the whole batch does not fit the tenant's limit; any error register raises for one item rejects the batch.

Every item is authorized before anything is written. Use it to import existing data or to register a parent and its children together (list the parent 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/resources/registerMany" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "resources": [
    {
      "type": "<type>",
      "id": "<id>"
    }
  ]
}'
Signature
iam.api.resources.registerMany(
  credential: CredentialInput,
  input: { tenantId: string; resources: ResourceInput[] },
): Promise<{ resources: ResourceRecord[] }>

update

Replaces a registered resource's attributes, or changes or clears its owner.

POST/api/iam/resources/update
client.resources.update()Credential
  • Permission: iam:resources:update on iam/{type}/{id}.
  • Audited as: iam:resources:update, on {type}/{id}.
  • Errors: NOT_FOUND when the resource is not registered or the new owner is not in this tenant; INVALID_INPUT for undeclared or wrongly typed attributes; INVALID_RESOURCE_TYPE; INVARIANT_VIOLATION when an enforced access invariant would newly fail.

attributes replaces the whole attribute set, so send every attribute you want to keep. ownerId: null removes the owner. Keep registrations current when the underlying record changes: a condition such as Bool: { 'resource.archived': false } sees only what was last registered. Offboarding a person with identities.offboard can transfer the resources they own to a successor.

Input

Prop

Type

Returns

A ResourceRecord 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/resources/update" \
  -H "Authorization: Bearer $BETTER_IAM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Better-IAM: 1" \
  -d '{
  "tenantId": "<tenantId>",
  "type": "<type>",
  "id": "<id>"
}'
Signature
iam.api.resources.update(
  credential: CredentialInput,
  input: {
    tenantId: string;
    type: string;
    id: string;
    attributes?: Record<string, Json>;
    ownerId?: string | null;
  },
): Promise<ResourceRecord>

Was this page helpful?

Better IAM is created by Sean Filimon

Last updated

On this page