---
title: "Permissions and access tokens"
description: "Look up permission targets, actions, organization roles, supported instance types, and access-token commands."
canonical_url: "https://docs.limrun.com/docs/reference/permissions"
markdown_url: "https://docs.limrun.com/docs/reference/permissions.md"
last_updated: "2026-11-14"
x_farming_labs_generated_preamble: true
---

# Permissions and access tokens
URL: /docs/reference/permissions
LLM index: /llms.txt
Description: Look up permission targets, actions, organization roles, supported instance types, and access-token commands.

# Permissions and access tokens

Permissions define what a credential can do. Use this reference when choosing API-key permissions, creating an access token, or assigning a workload role. The same permission syntax appears in all three places, but each accepts different grants.

## Permission syntax

A permission is `resource:target:action`, such as `android:android_euna_01h455vb4pex5vsknk084sn02q:all` or `asset:name/releases/app.ipa:read`.

The fields have these meanings:

| Field | Meaning |
| --- | --- |
| `resource` | A resource name from the tables below. Organization admin roles can also grant `*:*:all`. |
| `target` | A resource ID, `*` for all resources of that kind in the organization, or `name/<name-or-pattern>` for assets. Each credential type restricts which targets it accepts. |
| `action` | An operation such as `read` or `upload`. `all` includes every action for that resource. The action wildcard is spelled `all`, never `*`. |

Use IDs exactly as the API returns them. The first and last colons separate the fields, so an asset name can contain colons. Names are literal, without percent encoding. Asset patterns support case-sensitive `*` and `?`, including across slashes and colons. See [asset permission targets](/docs/platform/asset-storage#delegated-asset-permissions).

## Instance types

Each instance type has its own permission resource. Xcode IDs use `sandbox_`, but their permission resource is `xcode`.

| Instance type | Permission resource | ID prefix | Access-token grant |
| --- | --- | --- | --- |
| iOS simulator | `ios` | `ios_` | `ios:<instance-id>:stream` or `ios:<instance-id>:all` |
| Android emulator | `android` | `android_` | `android:<instance-id>:stream` or `android:<instance-id>:all` |
| Xcode sandbox | `xcode` | `sandbox_` | `xcode:<instance-id>:all` |
| Gradle sandbox | `gradle` | `gradle_` | `gradle:<instance-id>:all` |

Instance actions have different uses and issuance rules:

| Action | Instance types | What it permits | Accepted by access-token create? |
| --- | --- | --- | --- |
| `read` | All four | Read instance records and supported persisted logs or snapshots, without control credentials. | No. Use an API key or member session with this permission. |
| `stream` | iOS, Android | Interactive screen streaming and supported viewer actions. | Yes, for one instance ID. |
| `all` | All four | Every action for the instance resource, subject to the endpoint's credential requirements. | Yes, for one instance ID. |
| `work` | Xcode, Gradle | Start a sandbox as a remote build worker, without general sandbox control. | No. The remote build service obtains these access tokens. |
| `tunnel` | iOS, Android | Access the instance's destination tunnel endpoints, without device control or streaming. | No. The private-tunnel flow issues these access tokens to connectors. |

The instance action `tunnel` differs from the resource permission `tunnel:<tunnel-id>:connect`, which lets a connector join a private tunnel. See [Private tunnels](/docs/networking/private-tunnels).

For API keys and organization roles, `read` permits instance records and supported persisted logs or snapshots. It does not return instance control credentials. `all` also permits creating, updating, deleting, and controlling instances, subject to the endpoint's credential requirements.

An instance access token with `all` grants control of one instance through its own endpoints. It does not grant organization-wide listing, instance creation, deletion, or role updates. Pass the instance's `status.apiUrl` and the new token to a device or build client. Your backend should supply the URL alongside the token. The management API accepts signed credentials only on selected endpoints; a token is not a drop-in replacement for an API key on every SDK method.

For iOS and Android, `stream` grants interactive streaming: screen viewing, touch, typing, and other supported viewer actions. It does not grant app installation, explicit app launch or termination, the device API, or ADB. Supply the instance's `status.endpointWebSocketUrl` alongside the token to a streaming client. A `stream` grant does not permit fetching the instance record to discover this URL. `all` includes `stream`.

The instance response also includes `status.streamToken`, an access token with the same streaming-only permission and no expiry. Tokens minted through the access-token create endpoint have a limited lifetime. The endpoint does not accept `read`, `work`, or `tunnel` as instance actions. Xcode and Gradle have no device screen stream.

## Access-token permissions

`POST /v1/access_tokens`, `lim access-token create`, and `lim.accessTokens.create()` accept the following permissions when called with an API key or login. Every permission must be covered by the caller's grants. The caller also needs `accesstoken:*:all` to create or revoke access tokens.

| Resource | Accepted target | Accepted actions | What the token permits |
| --- | --- | --- | --- |
| `ios` | One iOS instance ID | `stream`, `all` | `stream` permits interactive streaming. `all` also permits device API and app-management operations. |
| `android` | One Android instance ID | `stream`, `all` | `stream` permits interactive streaming. `all` also permits device API, ADB, and app-management operations. |
| `xcode` | One Xcode instance ID | `all` | Use that sandbox's build, command, and file endpoints. |
| `gradle` | One Gradle instance ID | `all` | Use that sandbox's build, command, and file endpoints. |
| `asset` | Asset ID, `name/<name-or-pattern>`, or `*` | `read`, `create`, `upload`, `update`, `delete`, `all` | Perform the asset operations described below. `create` requires a name target or `*`. |
| `device` | `*` | `install` | Start physical-device installation sessions. Also requires `asset:<target>:read` for the asset being installed. |
| `applerelay` | `*` | `connect` | Open the Apple Account authentication relay. Apple credentials remain separate. |
| `remotecache` | `*` | `read`, `all` | Read Bazel cache entries and blobs; `all` also permits writing cache entries and blobs. |
| `remoteexecution` | `*` | `all` | Run actions through the Bazel remote execution service. |

Instance grants require concrete IDs; `android:*:all`, for example, is rejected. Asset permissions apply to assets used by any instance type. `device` refers to installation on physical devices, not iOS simulators or Android emulators. The cache and remote execution permissions belong to the organization's Bazel service, not to one sandbox.

These are the asset actions:

| Action | Effect |
| --- | --- |
| `read` | Read asset metadata and obtain download URLs. Listing requires a grant covering the requested selection. |
| `create` | Create an asset record at a name that does not yet exist. Does not permit uploading bytes by itself. |
| `upload` | Obtain upload URLs and upload bytes to an asset. Add `create` if the asset may not exist yet. |
| `update` | Change asset metadata, such as its display name or expiry. |
| `delete` | Delete the asset. |
| `all` | All asset actions for the target. |

Delegating an asset name pattern containing `*` or `?` requires `asset:*:<action>` or a broader grant. A credential holding only a name pattern can delegate matching concrete names, but cannot delegate another pattern, even an identical one.

### Create and revoke

The CLI supports repeated `--permission` flags:

```bash
lim access-token create \
  --permission "android:$INSTANCE_ID:all" \
  --ttl-seconds 900 \
  --json

lim access-token revoke "$TOKEN_ID"
# Or pass the token itself:
lim access-token revoke "$ACCESS_TOKEN"
```

`--json` returns the API response, including `id`, `token`, `permissions`, and `expiresAt`. Save `id` for revocation. `--quiet` prints only the token value; `--quiet --json` keeps the JSON response. CLI revocation accepts either the ID or the `lim_st_...` token value. For a token, it extracts the JWT `jti` and sends that ID to the API, authenticated with your API key or login. Tokens without a `jti`, such as `status.token` and `status.streamToken`, cannot be revoked this way. The SDK and REST revoke methods still take an ID.

To grant only interactive streaming, use `stream` for an iOS or Android instance:

```bash
lim access-token create \
  --permission "ios:$INSTANCE_ID:stream" \
  --ttl-seconds 900 \
  --json
```

The TypeScript SDK exposes the same operations:

```ts
import Limrun from '@limrun/api';

const lim = new Limrun(); // Reads LIM_API_KEY.
const access = await lim.accessTokens.create({
  permissions: [`xcode:${instance.metadata.id}:all`],
  ttlSeconds: 900,
});

// Supply instance.status.apiUrl and access.token to the sandbox client.
// When this credential is no longer needed:
await lim.accessTokens.revoke(access.id);
```

For REST clients, create with `POST /v1/access_tokens` and revoke with `DELETE /v1/access_tokens/{id}`. Authenticate both calls with your API key in the `Authorization: Bearer ...` header. The create body uses `permissions` and optional `ttlSeconds`.

### Lifetime and revocation

Tokens created with an API key or login default to 3,600 seconds. `ttlSeconds` accepts integers from 1 through 14,400. Workload-identity exchanges default to 600 seconds and accept only shorter lifetimes.

Revocation applies to the individual token ID. It leaves the minting API key, other access tokens, and running instances unchanged. Repeating a revoke call is safe.

The management and registry APIs reject revoked tokens once the revocation has propagated. Instance endpoints verify tokens offline and do not check revocation. They continue accepting an otherwise valid access token until it expires or the instance terminates. Revocation does not close an existing connection. Choose the lifetime with these limits in mind.

## Organization roles and API keys

Organization membership has three built-in roles: `admin`, `member`, and `viewer`. Admin has `*:*:all`. The following table lists each role's grants; `all` includes `read` where supported. A dash means the role has no grant for that resource.

| Resource | What it governs | Admin | Member | Viewer |
| --- | --- | --- | --- | --- |
| `ios`, `android`, `xcode`, `gradle` | Instance records, lifecycle, control, and supported logs or snapshots | `all` | `all` | `read` |
| `asset` | Asset metadata and stored files | `all` | `all` | `read` |
| `secret` | Stored signing secrets; `read` lists metadata, `all` also reads secret contents and writes or deletes secrets | `all` | `all` | — |
| `apikey` | List, create, and delete API keys | `all` | `all` | — |
| `accesstoken` | Create and revoke access tokens | `all` | `all` | — |
| `device` | Physical-device installation | `install` | `install` | — |
| `applerelay` | Apple Account relay connections | `connect` | `connect` | — |
| `remotecache` | Read or write the organization's Bazel cache | `all` | `all` | `read` |
| `remoteexecution` | Execute Bazel actions | `all` | `all` | — |
| `analytics` | Usage analytics | `read` | `read` | `read` |
| `organization` | Organization settings, domains, SSO, provisioning, and webhooks | `all` | `read` | `read` |
| `member` | Organization members and invitations | `all` | `read` | `read` |
| `billing` | Billing details, invoices, and subscription changes | `all` | — | — |
| `tunnel` | List private tunnels; `all` also creates, updates, deletes, and issues connector tokens | `all` | `read` | `read` |
| `nodepool` | List node pools; `all` also creates, resizes, and deletes them | `all` | `read` | `read` |

API keys and CLI login credentials receive their creator's permission bundle without organization, member, billing, or API-key administration permissions, or a requested subset. They use `*` targets; per-instance IDs belong to access tokens. Explicit `stream` and `tunnel` actions are not accepted in API-key permission requests.

Permission alone does not change the kinds of credentials an endpoint accepts. API-key administration and organization membership or billing operations require a member session. An API key cannot administer other API keys just because its bundle contains `apikey:*:all`.

The `tunnel:<tunnel-id>:connect` permission authorizes a private-tunnel connector. Tunnel credentials come from [private-tunnel create and rotate operations](/docs/networking/private-tunnels), not the access-token create endpoint.

## Workload roles

All four instance types accept an inline `spec.role.permissions` array. This grants the workload access to other resources. It does not limit a separate credential supplied to a process, and it does not change who can control the instance.

Workload roles currently accept only the asset permissions listed above. Named role references such as `admin` or `viewer` are not supported. An explicit `role: { permissions: [] }` grants nothing. Omitting the role uses the organization's compatibility default, so use an explicit list to choose access deliberately.

Code inside a workload can exchange its identity for an access token carrying its current role or a nonempty subset. It cannot expand its role or renew using the access token alone. See [Workload Identity](/docs/platform/workload-identity) for creation, updates, and exchanges.

## Compatibility names

Use `accessTokens`, `/v1/access_tokens`, and `permissions` in new integrations. The deprecated SDK property `scopedTokens`, REST path `/v1/scoped_tokens`, request field `scopes`, and permission resource `scopedtoken` remain compatibility aliases. They refer to access tokens. If a request supplies both `permissions` and `scopes`, their sets must match.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
