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.
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.
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:
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:
lim access-token create \
--permission "ios:$INSTANCE_ID:stream" \
--ttl-seconds 900 \
--jsonThe TypeScript SDK exposes the same operations:
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, 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 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.
Look up permission targets, actions, organization roles, supported instance types, and access-token commands.
Was this guide helpful?