Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/pr-assets/app-preview-api-key-docs.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion apps/docs/src/content/docs/docs/cli/reference/channel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,17 @@ npx @capgo/cli@latest channel delete production com.example.app
| Param | Type | Description |
| -------------- | ------------- | -------------------- |
| **-a** | <code>string</code> | API key to link to your account |
| **--delete-bundle** | <code>boolean</code> | Delete the bundle associated with the channel |
| **--delete-bundle** | <code>boolean</code> | Delete the bundle associated with the channel. After the App Preview lifecycle release, an App Preview key can atomically delete only its own preview channel and bundle. |
| **--success-if-not-found** | <code>boolean</code> | Success if the channel is not found |
| **--supa-host** | <code>string</code> | Custom Supabase host URL (for self-hosting or Capgo development) |
| **--supa-anon** | <code>string</code> | Custom Supabase anon key (for self-hosting) |

:::caution
**Availability:** The special App Preview cleanup requires the App Preview lifecycle release. Until that release is deployed to your Capgo Cloud environment, `--delete-bundle` requires the general `bundle.delete` permission and is not available to an App Preview key.

After the release, use an organization- and app-bound **App Preview** API key with `--delete-bundle`. The command uses a narrow atomic cleanup route: it succeeds only for the channel and linked bundle that key created. The key cannot use it on a default/main channel, another preview key's channel, or another key's bundle, and it still does not receive general `bundle.delete`. See [API Keys](/docs/webapp/api-keys/#use-an-app-preview-key-for-preview-workflows) for setup.
:::

### <a id="channel-list"></a> 📋 **List**

**Alias:** `l`
Expand Down
49 changes: 40 additions & 9 deletions apps/docs/src/content/docs/docs/public-api/api-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,43 @@ The `authorization` header is also accepted but is primarily intended for JWT to

## RBAC Permissions

API keys use the same role-based access control (RBAC) system as user accounts. When creating or managing keys through the web app, you assign roles at two levels:
API keys use the same role-based access control (RBAC) system as user accounts. When creating or managing keys through the web app or API, you assign roles at two levels:

- **Organization role** — Defines the key's baseline permissions across the entire organization (e.g. `org_admin`, `org_member`).
- **App roles** — Optional per-app permissions (e.g. `app_admin`, `app_developer`, `app_uploader`, `app_reader`).
- **Organization role** — Defines the key's baseline permissions across the entire organization (for example, `org_admin` or `org_member`).
- **App roles** — Per-app permissions (for example, `app_admin`, `app_developer`, `app_uploader`, `app_reader`, or `app_preview`).

If an API key has explicit role bindings, **only those bindings** are evaluated for permission checks. The key owner's personal permissions are not inherited by the key.

### Preview channel automation

After the App Preview lifecycle release is deployed to your Capgo Cloud environment, bind `app_preview` only to the preview app for CI that creates a temporary preview channel, uploads and promotes a bundle, then deletes both. Until then, `--delete-bundle` requires the general `bundle.delete` permission and is not available to an App Preview key.

```json
{
"name": "PR preview key",
"hashed": true,
"bindings": [
{
"role_name": "app_preview",
"scope_type": "app",
"org_id": "<OWNING_ORG_UUID>",
"app_id": "<APP_UUID>"
}
]
}
```
`org_id` is the UUID of the app's owning organization. `app_id` is the app record's internal UUID, not the public app identifier used by CLI commands (for example, `com.example.app`). The binding remains organization-bound even when the key has no organization-wide role.

The app-level `app_preview` role includes only `app.read`, `app.read_bundles`, `app.upload_bundle`, and `app.create_channel`. When that key creates a channel, Capgo automatically adds a `channel_preview` binding on the newly created channel. That child binding grants `channel.read`, `channel.promote_bundle`, and `channel.delete` only for the channel the key created.

`app_preview` retains `app.read`, so this is not strict channel-read isolation: the key may enumerate channel metadata in the selected app. The automatic child binding limits **lifecycle mutations** to the channel the key created.

Capgo records the App Preview key that uploaded each bundle. The key can promote only its own bundle to its own preview channel. It has no channel lifecycle access to an existing default/main channel, a channel created by another preview key, or another key's bundle.

Use `channel delete <preview-channel> <public-app-id> --delete-bundle` for cleanup. This is an atomic, ownership-checked preview cleanup route; it removes only the calling key's preview channel and linked bundle. `app_preview` does not grant generic `bundle.delete`.

For the dashboard setup and a complete CLI example, see [Use an App Preview key for preview workflows](/docs/webapp/api-keys/#use-an-app-preview-key-for-preview-workflows).

{/* [SCREENSHOT: capgo_apikeys_rbac_diagram.webp] — Diagram showing the RBAC hierarchy: org roles → app roles → API key permissions */}
<figure><img style="margin-left: auto; margin-right: auto" src="/capgo_apikeys_rbac_diagram.webp" alt="A diagram explaining how RBAC API key permissions work" /><figcaption></figcaption></figure>

Expand Down Expand Up @@ -94,12 +124,13 @@ Organization policies can enforce:

## Common Use Cases

1. **CI/CD Integration**: Create keys scoped to specific apps with the `app_uploader` or `app_developer` role, and set an expiration date
2. **Deployment Automation**: Use keys with the `app_developer` role for automated deployment scripts
3. **Monitoring Tools**: Create keys with the `app_reader` role for external monitoring integrations
4. **Admin Access**: Use keys with the `org_admin` role sparingly for administrative tools
5. **Third-Party Integrations**: Create keys restricted to specific apps with the minimum required role
6. **Organization Provisioning**: Use an `org_admin` or `org_super_admin` RBAC key with `org.create` only for trusted automation that needs to create organizations
1. **CI/CD Integration**: Create keys scoped to specific apps with the `app_uploader` or `app_developer` role, and set an expiration date.
2. **PR Preview Channels**: Use `app_preview` on only the preview app or apps when CI needs to upload a bundle, create a temporary channel, and atomically clean up its own channel and bundle.
3. **Deployment Automation**: Use keys with the `app_developer` role for automated deployment scripts.
4. **Monitoring Tools**: Create keys with the `app_reader` role for external monitoring integrations.
5. **Admin Access**: Use keys with the `org_admin` role sparingly for administrative tools.
6. **Third-Party Integrations**: Create keys restricted to specific apps with the minimum required role.
7. **Organization Provisioning**: Use an `org_admin` or `org_super_admin` RBAC key with `org.create` only for trusted automation that needs to create organizations.

## Keep going from API Keys

Expand Down
80 changes: 62 additions & 18 deletions apps/docs/src/content/docs/docs/webapp/api-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar:
order: 5
---

API keys are managed at the organization level with role-based access control (RBAC). Each key can be assigned an organization-wide role and optional per-app roles, giving you fine-grained control over what each key can access.
API keys use role-based access control (RBAC). A key can have an organization-wide role, app-scoped bindings, or both. Every app binding remains associated with that app's owning organization. For least privilege, restrict a key to selected apps instead of assigning an organization-wide role.

## Where are API keys managed?

Expand All @@ -24,40 +24,84 @@ The page displays two sections:
1. Click the **"+"** button at the top of the RBAC keys table.

2. Fill in the **Key information**:
- **Name** (required) — A descriptive label for the key (e.g. "CI/CD Deploy", "Monitoring Read-Only").
- **Create secure key** (optional) — When checked, the key will be hashed server-side. The plain-text key is shown **only once** after creation. You will not be able to retrieve it later.
- **Set expiration date** (optional) — Pick a date after which the key will stop working. Some organizations enforce mandatory expiration via policy.
- **Name** (required) — A descriptive label for the key (for example, "CI/CD Deploy" or "Monitoring Read-Only").
- **Create secure key** (optional) — When checked, the key is hashed server-side. The plain-text key is shown **only once** after creation and cannot be retrieved later.
- **Set expiration date** (optional) — Pick a date after which the key stops working. Some organizations enforce mandatory expiration through policy.

{/* [SCREENSHOT: apikeys-create-form.webp] — The creation form showing Name field, "Create secure key" checkbox, and expiration date picker */}
<figure><img src="/apikeys-create-form.webp" alt="API key creation form with name, secure key option, and expiration" /><figcaption></figcaption></figure>

3. Select an **Organization role** — This defines the key's baseline permissions across the entire organization. Available roles (depending on your own role level):
- **None** — No org-wide access; the key only has access to individually assigned apps.
- **Member** — Basic read access to the organization.
- **Admin** — Full administrative access to the organization (inherits access to all apps).
3. Choose the key scope:
- **Organization-wide access** — Select an **Organization role** to define baseline permissions across the organization. Available roles depend on your own role level:
- **None** — No organization-wide access.
- **Member** — Basic read access to the organization.
- **Admin** — Full administrative access to the organization and all its apps.
- **App-only access** — Enable **Limit this key to selected apps**. Each app binding remains linked to that app's owning organization; this mode omits only an organization-wide RBAC role.

4. If the key needs to create organizations through the public API, enable **Allow creating organizations**.

This adds the global `org.create` permission. It is available when the key has an Admin organization role. When this key creates a new organization, Capgo automatically assigns the key as Super Admin on that new organization.

5. If the selected org role is not Admin, you can add **per-app access**:
- Click **"+ Add App"** to open the app picker.
- Select one or more apps, then assign a role to each:
- **App Reader** — Read-only access to the app.
- **App Uploader** — Can upload new bundles.
- **App Developer** — Can manage the app configuration and deployments.
- **App Admin** — Full access to the app.
This adds the global `org.create` permission. The key also needs an organization-scoped `org_admin` or `org_super_admin` binding. In the dashboard, selecting **Admin** creates the `org_admin` binding. When this key creates a new organization, Capgo automatically assigns the key as Super Admin on that new organization.

5. To grant app access:
- When **Limit this key to selected apps** is enabled, choose an organization under **Organizations to filter apps** to reveal its apps. The selected app bindings remain associated with their owning organizations; this filter does not grant organization-wide access.
- Click **"+ Add App"**, select one or more apps, then assign a role to each:
- **App Reader** — Read-only access to the app.
- **App Uploader** — Can upload new bundles.
- **App Developer** — Can upload bundles, manage devices, trigger native builds, and update channel settings.
- **App Admin** — Full access to the app.
- **App Preview** — Preview CI/CD lifecycle: upload a bundle and create a preview channel. The channel receives automatic, channel-scoped lifecycle rights only for this key.
{/* [SCREENSHOT: apikeys-rbac-roles.webp] — The role selection section showing org role radio buttons and the per-app role assignment table */}
<figure><img src="/apikeys-rbac-roles.webp" alt="RBAC role selection with org-level and per-app roles" /><figcaption></figcaption></figure>

6. Click **"Create"**.

7. If you checked "Create secure key", a modal will display the plain-text key. **Copy it immediately** — it cannot be retrieved after closing the modal.
7. If you checked **Create secure key**, a modal displays the plain-text key. **Copy it immediately** — it cannot be retrieved after closing the modal.

{/* [SCREENSHOT: apikeys-secret-modal.webp] — The one-time secret modal showing the plain-text key with a copy button */}
<figure><img src="/apikeys-secret-modal.webp" alt="One-time API key secret modal with copy button" /><figcaption></figcaption></figure>

## Use an App Preview key for preview workflows

Use **App Preview** for CI that creates a temporary preview channel, uploads and promotes a bundle, then removes both the channel and bundle. It is designed for PR previews without granting control over the app's default or main channels.

:::caution
**Availability:** This ownership-bound lifecycle requires the App Preview lifecycle release. Until that release is deployed to your Capgo Cloud environment, `--delete-bundle` requires the general `bundle.delete` permission and an App Preview key cannot use it.
:::

1. Create an RBAC key and enable **Limit this key to selected apps**.
2. Under **Organizations to filter apps**, select the organization to reveal its apps; each selected app remains associated with its owning organization.
3. Add only the app or apps used for preview deployments.
4. Select **App Preview** for each selected app.
5. Create a secure key, set an expiration date when appropriate, and store it in your CI secret manager.

This selected-apps-only mode omits an organization-wide role; it does **not** remove the organization association. Each `app_preview` binding remains scoped to its selected app and that app's owning organization.

| Grant | Permissions and boundary |
| --- | --- |
| `app_preview` on the selected app | `app.read`, `app.read_bundles`, `app.upload_bundle`, and `app.create_channel`. |
| Automatic `channel_preview` binding | When this key creates a channel, Capgo automatically gives the key `channel.read`, `channel.promote_bundle`, and `channel.delete` for that channel only. |

`app_preview` retains `app.read`, so the key may enumerate channel metadata in the selected app. The automatic child binding is a **management** boundary: it does not grant lifecycle mutations for channels the key did not create.

Capgo also records which App Preview key uploaded a bundle. The key can set only its own bundle on its own preview channel and can clean up that pair together. It does not receive a channel binding for an existing default or main channel, a channel created by another preview key, or another key's bundle.

For a typical CI job, use a unique channel name per pull request:

```bash
npx @capgo/cli@latest channel add "$PREVIEW_CHANNEL" com.example.app -a "$CAPGO_API_KEY"
npx @capgo/cli@latest bundle upload com.example.app --path ./dist -b "$BUNDLE_VERSION" -a "$CAPGO_API_KEY"
npx @capgo/cli@latest channel set "$PREVIEW_CHANNEL" com.example.app --bundle "$BUNDLE_VERSION" -a "$CAPGO_API_KEY"
npx @capgo/cli@latest channel delete "$PREVIEW_CHANNEL" com.example.app --delete-bundle -a "$CAPGO_API_KEY"
```

The last command uses a narrow atomic cleanup route: it succeeds only when the key owns the preview channel and its linked bundle. **App Preview** still does not have general `bundle.delete`, so it cannot delete an arbitrary bundle.

:::caution
An **App Preview** key cannot promote, delete, or change an existing default/main channel, another preview key's channel, or another key's bundle. Revoking or expiring the app binding also removes the key's effective lifecycle access.
:::

See the [Access Control Reference](/docs/webapp/organization-roles/#app-preview-permission-set) for the full boundary.

## How to manage (edit) an API key?

Click the **wrench icon** (Manage) on any RBAC key in the list. This opens the key detail page where you can:
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/src/content/docs/docs/webapp/channels.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ If the trash icon is not visible, your account does not have the `channel.delete
npx @capgo/cli@latest channel delete <channel-name> <app-id>
```

After the App Preview lifecycle release is deployed to your Capgo Cloud environment, an organization- and app-bound **App Preview** key can atomically delete only the preview channel and bundle it created with `channel delete <preview-channel> <app-id> --delete-bundle`. Until that release, `--delete-bundle` requires the general `bundle.delete` permission and is not available to an App Preview key. After release, it cannot change or delete an existing default/main channel, another preview key's channel, or another key's bundle. See [API Keys](/docs/webapp/api-keys/#use-an-app-preview-key-for-preview-workflows) for the least-privilege setup.

## Managing a channel

Clicking on the channel name will open a modal where you can manage the channel settings. (`3` in the image)
Expand Down
Loading