Topolo Docs Topolo Platform
Open workspace

List grants for resource

List a bounded page of live grants for one exact application resource the caller can manage.

Outcome

List a bounded page of live grants for one exact application resource the caller can manage.

These examples prove local handler behavior with real isolated SQL and explicitly simulated identity/permission dependencies.

Before you start

  • Verify identity and the current credential-scoped action contract before preparing input. Resource-grant operations authorize the target organization/app at runtime; metadata discovery does not prove execution permission.

  • Discover the recipient and existing application resource. Use one exact organization/app/type/id tuple consistently; a grant never creates the target resource.

Discover the target

topolo whoami --json
topolo apps --json
topolo actions get app_topolo_auth.resource_grants.list_resource --detail --json

Discover the recipient and target resource using owning-application actions. Read app_topolo_auth.resource_grants.list_resource with the exact resource tuple and follow all pages.

Input fields

FieldRequiredMeaning
organization_idYesExact organization owning the resource. Use the same organization/app/type/id tuple as the grant; this is not an organization-wide recipient listing.
app_idYesExact stored application identifier to filter grants. App id and slug are not interchangeable in grant storage or list filters.
resource_typeYesExact resource kind paired with resource_id. For list_mine both filters must be supplied together; list_resource requires both.
resource_idYesExact resource id paired with resource_type; no wildcard discovery of recipients.
limitNoPage size from 1 to 100, default 50. Preserve the same filters when following nextCursor.
cursorNoOpaque continuation copied from the previous page.nextCursor; do not construct one from examples. Pagination is keyset-based on createdAt/id and is not a snapshot of concurrent grant changes.

Effects

  • Reads a bounded page of recipients for one exact resource the caller may manage.

Interpret the response

The raw target success envelope is success/message/data/timestamp. Create returns HTTP 201; all other successes return 200. CLI and MCP may wrap or project this envelope.

Grant id and createdAt remain stable when create updates the same user/organization/app/resourceType/resourceId key or reactivates a revoked grant. Omitted scope/type/metadata/expiry reset to create defaults rather than preserve previous values. Take a snapshot before replacing an existing grant.

Live lists omit revoked and expired rows. page.hasMore controls continuation; nextCursor is null at the end. list_mine contains only the authenticated subject, never a supplied userId. list_resource additionally returns recipient id/email/name or null when identity lookup is unavailable.

Create data.provisioned means this call created an unverified identity. It does not imply membership, invitation, sign-in, recipient acceptance or resource access. A create with past expiry can succeed with data.grant null because its stored row is already absent from live access.

Grant createdAt, expiresAt and revokedAt are epoch seconds; response timestamp is ISO text. Legacy create expiry strings can remain strings in stored output. Convert dates before planning; never infer live access from a successful storage response.

Update preserves identity and can extend an expired unrevoked grant. A revoked row is refused. Revoke returns only data.id, including on repeated revocation, and does not delete the recipient identity or affect separate membership/other grants.

Promote creates organization membership before revoking all non-workspace resource grants for that user and organization across apps. appId limits the permission check, not the revocation scope. These writes span databases and are not atomic; a 500 can leave membership active while grants remain. Read membership/effective access and remaining grants before any reviewed retry or compensation.

Promote data.role echoes the requested/default role. Existing membership, stored user role and effective authorization require separate verification. Notification delivery is nonfatal and is not proven by success. An empty list_mine after promotion does not mean the user has lost organization access.

AUTH_ERROR (401) is used both for absent/invalid tokens and for authenticated callers lacking organization or app grant authority. Inspect the error and identity before assuming OAuth expired; preserve authorization denials rather than changing credential context automatically.

Worked examples

These are complete raw target-handler responses, not CLI/gateway envelopes or live authorization proof. Replace synthetic identifiers using authorized discovery. Save only the reviewed input as payload.json; inspect validation and plan before executing. --confirm assumes the intended operation is approved. Metadata read-back requires separate recipient-principal and owning-application access tests.

Manager gets first page with recipient identities and continuation

Input · payload.json:

{
  "organization_id": "org_example",
  "app_id": "app_topolo_people",
  "resource_type": "candidate",
  "resource_id": "candidate_one",
  "limit": 1
}

CLI:

topolo actions validate app_topolo_auth.resource_grants.list_resource --data @payload.json --json
topolo actions plan app_topolo_auth.resource_grants.list_resource --data @payload.json --json
topolo actions call app_topolo_auth.resource_grants.list_resource --data @payload.json --json

MCP call after validation and plan review:

{
  "tool": "topolo_read_action",
  "arguments": {
    "actionId": "app_topolo_auth.resource_grants.list_resource",
    "input": {
      "organization_id": "org_example",
      "app_id": "app_topolo_people",
      "resource_type": "candidate",
      "resource_id": "candidate_one",
      "limit": 1
    }
  }
}

Captured local handler response · HTTP 200:

{
  "success": true,
  "message": "Resource grants fetched",
  "data": {
    "grants": [
      {
        "id": "rg_JOD6QZYnE1JA",
        "userId": "usr_recipient",
        "organizationId": "org_example",
        "appId": "app_topolo_people",
        "resourceType": "candidate",
        "resourceId": "candidate_one",
        "grantType": "consumer",
        "scope": "read_write",
        "expiresAt": null,
        "grantedBy": "usr_operator",
        "metadata": {
          "purpose": "interview"
        },
        "revokedAt": null,
        "createdAt": 1790964100,
        "recipient": {
          "id": "usr_recipient",
          "email": "recipient@example.test",
          "name": "Recipient"
        }
      }
    ],
    "page": {
      "nextCursor": "1790964100:rg_JOD6QZYnE1JA",
      "hasMore": true
    }
  },
  "timestamp": "2026-10-02T18:01:40.145Z"
}

Next page completes exact resource discovery

Input · payload.json:

{
  "organization_id": "org_example",
  "app_id": "app_topolo_people",
  "resource_type": "candidate",
  "resource_id": "candidate_one",
  "limit": 1,
  "cursor": "1790964100:rg_JOD6QZYnE1JA"
}

CLI:

topolo actions validate app_topolo_auth.resource_grants.list_resource --data @payload.json --json
topolo actions plan app_topolo_auth.resource_grants.list_resource --data @payload.json --json
topolo actions call app_topolo_auth.resource_grants.list_resource --data @payload.json --json

MCP call after validation and plan review:

{
  "tool": "topolo_read_action",
  "arguments": {
    "actionId": "app_topolo_auth.resource_grants.list_resource",
    "input": {
      "organization_id": "org_example",
      "app_id": "app_topolo_people",
      "resource_type": "candidate",
      "resource_id": "candidate_one",
      "limit": 1,
      "cursor": "1790964100:rg_JOD6QZYnE1JA"
    }
  }
}

Captured local handler response · HTTP 200:

{
  "success": true,
  "message": "Resource grants fetched",
  "data": {
    "grants": [
      {
        "id": "rg_6nDEPU6LsT4w",
        "userId": "usr_second",
        "organizationId": "org_example",
        "appId": "app_topolo_people",
        "resourceType": "candidate",
        "resourceId": "candidate_one",
        "grantType": "consumer",
        "scope": "read",
        "expiresAt": null,
        "grantedBy": "usr_manager",
        "metadata": null,
        "revokedAt": null,
        "createdAt": 1790964100,
        "recipient": {
          "id": "usr_second",
          "email": "second@example.test",
          "name": null
        }
      }
    ],
    "page": {
      "nextCursor": null,
      "hasMore": false
    }
  },
  "timestamp": "2026-10-02T18:01:40.146Z"
}

Verify the result

  • Read list_resource for the exact organization/application/type/id and compare recipient, scope and expiry against the intended change; follow all pages.

  • Use the intended recipient principal with list_mine, then verify the owning application accepts only the intended resource/scope and denies an unrelated resource. Metadata read-back alone does not prove resource enforcement.

Errors and recovery

Authenticated recipient cannot enumerate other recipients

Captured local refusal · HTTP 401:

{
  "input": {
    "organization_id": "org_example",
    "app_id": "app_topolo_people",
    "resource_type": "candidate",
    "resource_id": "candidate_one"
  },
  "response": {
    "success": false,
    "error": {
      "message": "Not authorized to list grants for this resource",
      "code": "AUTH_ERROR",
      "details": null,
      "timestamp": "2026-10-02T18:01:40.150Z"
    }
  }
}

Published recovery guidance

  • VALIDATION_ERROR (HTTP 400): Correct reported fields. Pair resource filters, preserve pagination cursors and use workspace access actions for workspace grants.

  • AUTH_ERROR (HTTP 401): Inspect identity and error message: invalid token and insufficient grant authority both use 401. Refresh an expired token when necessary; obtain intended access through its authorized owner for permission denials.

  • NOT_FOUND (HTTP 404): Rediscover the exact live resource grant. Revoked rows cannot be updated; creation reactivation is a separate reviewed access grant.

  • SERVER_ERROR (HTTP 500): Inspect actual stored state before retrying. Create can fail after identity provisioning; promote can fail after membership creation. Correct unsupported SQL-constrained scope/type input; do not treat a failure as proof that nothing changed.

Recovery boundaries

Read-only; do not widen the organization or resource filter to recover from a denial.

Discovery and evidence

This record belongs to app_topolo_auth. Local tests prove real resource-grant SQL and handler responses with simulated identity, permissions, identity lookup/provisioning and stored-role synchronization. They do not prove recipient sign-in, invitation delivery, owning-application resource enforcement, live permissions, deployment or production completion.