Hierarchical and cross-account access¶
DotID lets you grant access along an organization’s shape, not just one account at a time. Two
capabilities cover this, both under the identity and organizations API families.
Resolve your organization¶
Every org-scoped route below needs an {orgId} in the path. If you only know your account id
(for example the account_id claim on your token), resolve the organization your account belongs to:
GET /identity/v1/accounts/{accountId}/organization
{
"account_id": "9a33e1b6-…",
"organization_id": "7b39dd74-…",
"name": "BROIT Portal",
"role": "management",
"ou_id": "5642e5b0-…",
"ou_name": "Root",
"ou_path": "root",
"mgmt_account_id": "9a33e1b6-…"
}
An account belongs to at most one organization — and resides in exactly one OU within it — so the
result is unambiguous. The response also tells you where the account sits in the tree: ou_id,
ou_name, and ou_path (the hierarchy as a dotted path, e.g. root.city.store-3; a management
account resides in its org’s Root OU). The call is self-scoped: you may resolve only the
organization of the account your credential is bound to (the accountId must match your access key’s
account, or your token’s account_id claim) — otherwise 403. An account that belongs to no
organization returns 404. Feed the returned organization_id into the {orgId} routes below.
OU-scoped permission assignment¶
Assign a permission set to a group on an organizational unit (OU) instead of on a single account. The grant then applies to every account in that OU’s subtree — including accounts you add later — so you don’t re-assign each account by hand.
# Assign permission set PS to group G on an OU; it cascades to accounts under that OU.
POST /identity/v1/organizations/{orgId}/ous/{ouId}/assignments
{ "group_id": "…", "permission_set_id": "…" }
# List / remove OU-scoped assignments
GET /identity/v1/organizations/{orgId}/ous/{ouId}/assignments
DELETE /identity/v1/organizations/{orgId}/ous/{ouId}/assignments/{id}
An account is covered when the assigned OU is one of its ancestors. An account outside that subtree is not granted anything by the assignment.
Transitive account-to-account delegation¶
An account can consent to another account exercising a set of its permission sets on its resources.
These consent edges compose transitively: a store → city → area → HQ chain of delegations lets a
principal in the top account act on the bottom account’s resources.
# Delegate scope you hold to another account
POST /identity/v1/accounts/{accountId}/delegations
{ "delegatee_account_id": "…", "scope_permission_set_ids": ["…"] }
# List delegations you granted / received; revoke one
GET /identity/v1/accounts/{accountId}/delegations
GET /identity/v1/accounts/{accountId}/delegations/received
DELETE /identity/v1/accounts/{accountId}/delegations/{delegationId}
Rules that keep delegation safe:
Scope only narrows. The effective scope is the intersection of the permission sets across every hop — a chain can never grant more than its weakest link.
You can only delegate what you hold. Each permission set in
scope_permission_set_idsmust be assigned to the delegating account, or the request is rejected (422).Bounded depth. Chains longer than the configured maximum are rejected (
422); a cycle is rejected (422).Immediate revocation.
DELETEon an edge takes effect on the very next authorization — there is no cached grant.
Access is evaluated per request: a valid, in-scope, non-revoked chain authorizes the action; anything else falls through to the normal deny.
These /identity/v1/accounts/{accountId}/delegations calls are reachable over AK/SK, authorized
for the delegating account itself or its organization’s management account — any other caller
gets a 403. To make one account a manager for a whole company’s accounts (an OU subtree, current
and future), the organization’s management account uses the OU → Manager delegation surface — see
Scoped delegation.