Llim.run

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:

FieldMeaning
resourceA resource name from the tables below. Organization admin roles can also grant *:*:all.
targetA 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.
actionAn 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 typePermission resourceID prefixAccess-token grant
iOS simulatoriosios_ios:<instance-id>:stream or ios:<instance-id>:all
Android emulatorandroidandroid_android:<instance-id>:stream or android:<instance-id>:all
Xcode sandboxxcodesandbox_xcode:<instance-id>:all
Gradle sandboxgradlegradle_gradle:<instance-id>:all

Instance actions have different uses and issuance rules:

ActionInstance typesWhat it permitsAccepted by access-token create?
readAll fourRead instance records and supported persisted logs or snapshots, without control credentials.No. Use an API key or member session with this permission.
streamiOS, AndroidInteractive screen streaming and supported viewer actions.Yes, for one instance ID.
allAll fourEvery action for the instance resource, subject to the endpoint's credential requirements.Yes, for one instance ID.
workXcode, GradleStart a sandbox as a remote build worker, without general sandbox control.No. The remote build service obtains these access tokens.
tunneliOS, AndroidAccess 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.

ResourceAccepted targetAccepted actionsWhat the token permits
iosOne iOS instance IDstream, allstream permits interactive streaming. all also permits device API and app-management operations.
androidOne Android instance IDstream, allstream permits interactive streaming. all also permits device API, ADB, and app-management operations.
xcodeOne Xcode instance IDallUse that sandbox's build, command, and file endpoints.
gradleOne Gradle instance IDallUse that sandbox's build, command, and file endpoints.
assetAsset ID, name/<name-or-pattern>, or *read, create, upload, update, delete, allPerform the asset operations described below. create requires a name target or *.
device*installStart physical-device installation sessions. Also requires asset:<target>:read for the asset being installed.
applerelay*connectOpen the Apple Account authentication relay. Apple credentials remain separate.
remotecache*read, allRead Bazel cache entries and blobs; all also permits writing cache entries and blobs.
remoteexecution*allRun 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:

ActionEffect
readRead asset metadata and obtain download URLs. Listing requires a grant covering the requested selection.
createCreate an asset record at a name that does not yet exist. Does not permit uploading bytes by itself.
uploadObtain upload URLs and upload bytes to an asset. Add create if the asset may not exist yet.
updateChange asset metadata, such as its display name or expiry.
deleteDelete the asset.
allAll 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 \
  --json

The 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.

ResourceWhat it governsAdminMemberViewer
ios, android, xcode, gradleInstance records, lifecycle, control, and supported logs or snapshotsallallread
assetAsset metadata and stored filesallallread
secretStored signing secrets; read lists metadata, all also reads secret contents and writes or deletes secretsallall—
apikeyList, create, and delete API keysallall—
accesstokenCreate and revoke access tokensallall—
devicePhysical-device installationinstallinstall—
applerelayApple Account relay connectionsconnectconnect—
remotecacheRead or write the organization's Bazel cacheallallread
remoteexecutionExecute Bazel actionsallall—
analyticsUsage analyticsreadreadread
organizationOrganization settings, domains, SSO, provisioning, and webhooksallreadread
memberOrganization members and invitationsallreadread
billingBilling details, invoices, and subscription changesall——
tunnelList private tunnels; all also creates, updates, deletes, and issues connector tokensallreadread
nodepoolList node pools; all also creates, resizes, and deletes themallreadread

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.