# OAuth for apps

How AI apps and MCP clients get access to a PX Studio account with OAuth 2.1, PKCE and dynamic client registration.

Apps that act for other streamers, like Claude or ChatGPT connectors, never see a password or a personal token. They use OAuth: the streamer signs in to PX Studio, sees exactly which permissions the app asks for and approves them. This page is for developers of such apps. To connect an existing AI app, see [Connect Claude and ChatGPT](/docs/connect-ai).

> [!NOTE]
> OAuth access tokens are bound to the MCP server at `https://pxstudio.cloud/mcp`. For your own scripts against the REST API, use a [personal token](/docs/api#personal-tokens) instead.

## Endpoints

| Purpose | Endpoint |
| --- | --- |
| Protected resource metadata (RFC 9728) | `GET /.well-known/oauth-protected-resource` |
| Authorization server metadata (RFC 8414) | `GET /.well-known/oauth-authorization-server` |
| Dynamic client registration (RFC 7591) | `POST /oauth/register` |
| Authorization (the consent screen) | `GET /oauth/authorize` |
| Token | `POST /oauth/token` |
| Revocation (RFC 7009) | `POST /oauth/revoke` |

All endpoints live on `https://pxstudio.cloud`. The metadata also announces support for client ID metadata documents.

## The flow

::: steps
**Discover.** Call the MCP server without a token. The `401` answer carries a `WWW-Authenticate` header with `resource_metadata`, which points to the protected resource metadata and from there to the authorization server.

**Register.** Register your client with `POST /oauth/register` (or use a client ID metadata document). Redirect URIs must use `https`; plain `http` is only allowed for loopback addresses.

**Authorize.** Send the streamer to `/oauth/authorize` with `response_type=code`, your `client_id`, the exact `redirect_uri`, a `state`, the `scope` you need, a PKCE `code_challenge` with `code_challenge_method=S256` and `resource=https://pxstudio.cloud/mcp`. They sign in if needed, review the app and the permissions, can untick any permission and click **Allow access**.

**Exchange.** Swap the code at `/oauth/token` with `grant_type=authorization_code` and your `code_verifier`. You get an access token and a refresh token.

**Call the MCP server** with `Authorization: Bearer <access token>`.
:::

## Rules

- **PKCE with S256 is required.** Requests without it are refused.
- **`resource` is required** and must be the MCP server URL.
- **Redirect URIs are compared exactly.** No wildcards, no extra query parameters.
- **Codes are single use** and valid for 5 minutes.
- **Access tokens last 1 hour.** Refresh with `grant_type=refresh_token`.
- **Refresh tokens rotate.** Each refresh returns a new refresh token. Using an old one again disconnects the app, which protects the streamer if a token leaks.
- Errors before the client and redirect URI are verified show an error page and never redirect. After that, errors return to your redirect URI with `state` and `iss`.

## Scopes

Ask only for what your app needs. The streamer can untick scopes on the consent screen, so handle a `403` with `insufficient_scope` gracefully: the answer's `WWW-Authenticate` header names the missing scope, and you can send the streamer through the flow again to ask for it.

| Scope | Name | What it allows |
| --- | --- | --- |
| `overlays:read` | Read overlays | See your overlays, their layers, scenes, settings and the widget catalog. |
| `overlays:write` | Design overlays | Create, rename, resize and delete overlays and move, resize, hide or lock layers. |
| `members:write` | Add and remove layers | Add widgets to an overlay and remove them. |
| `fields:write` | Change widget settings | Change the settings (text, colors, sources) of widgets on your overlays. |
| `scenes:write` | Edit scenes | Create, rename, delete and prepare scenes and previews. |
| `scenes:golive` | Switch scenes on air | Put a scene live on your stream output. |
| `actions:fire` | Trigger widgets on air | Fire widget commands and send test alerts that show on stream. |
| `uploads:write` | Upload media | Upload images, videos, audio and fonts to your media library. |
| `bot:read` | Read bot settings | See your PXStudioBot commands and settings. |
| `bot:write` | Change the bot | Create and change PXStudioBot commands and control bot features. |
| `account:read` | Read your account | See your account name, plan and stream statistics. |
| `stream:write` | Change stream info | Change the title and category of your Twitch stream. |
| `chat:write` | Send chat messages | Send messages to your stream chat as your account. |
| `chat:moderate` | Moderate chat | Delete messages, time out, ban and unban viewers and change chat modes. |
| `automations:read` | Read automations | See your automation rules and their activity. |
| `automations:write` | Change automations | Create, change, switch and delete your automation rules. |
> [!IMPORTANT]
> A token can never do more than the account behind it. Scopes only filter which operations an app may call; every call still runs through the same permission checks as the editor, including team roles on shared overlays.

## Connected apps

Streamers see every connected app under **Settings** → **API & AI apps** and can disconnect it there at any time. Changes an app makes show up in the overlay **History** with the app's name.
