> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryflowy.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Flowy is a node-based AI creative platform: you generate images, video, audio, 3D and vector on an infinite Canvas, refine on the Studio timeline, and export or publish from the same project.
> Prefer the Flowy MCP server (https://mcp.tryflowy.ai/mcp) or the REST API at https://apis.tryflowy.ai/v1 for programmatic work. Install with `flowy mcp install` from the @flowy/cli package.
> Credits are workspace-scoped. Generations reserve credits on start and only deduct on success, so failed runs refund automatically.

# OAuth apps

> Build a third-party integration that connects to a user's Flowy account with scoped, revocable access.

An **OAuth app** lets your product connect to a user's Flowy account without ever handling their password or an API key: the user signs in and approves exactly the scopes your app asks for, and can revoke that access at any time. This is the same mechanism the [Flowy MCP](/api/mcp) uses under the hood, generalized for your own integration.

<Note>
  This is a separate scope model from [dashboard API keys](/api/permissions): API keys carry `apps:read` / `apps:write` / `runs:read` / `runs:write` for one workspace; OAuth apps request from the broader list in [Scopes](#scopes) below and are account-bound, like the MCP.
</Note>

## Register an app

<Steps>
  <Step title="Open OAuth apps settings">
    Go to [Settings → OAuth apps](/settings/oauth-apps) and select **Create OAuth app**. You need to be a workspace **owner** or **editor**.
  </Step>

  <Step title="Fill in app details">
    Name, an optional description and website (shown to users on the consent screen), and an optional logo.
  </Step>

  <Step title="Pick a client type">
    * **Confidential**: a server-side app. Gets a **client secret**; keep it server-side.
    * **Public (PKCE)**: an SPA, CLI, or native app. No secret is issued; the app must use PKCE.

    The client type is fixed at creation. It can't be changed later.
  </Step>

  <Step title="Add redirect URIs">
    Where Flowy sends users back after they authorize. Each URI must be an absolute URL, `https://` (except `http://localhost` / `127.0.0.1`, for development), with no `#fragment`.
  </Step>

  <Step title="Pick scopes">
    Choose the most your app will ever need to request (see [Scopes](#scopes)). A specific authorization can request the same set or a subset. Pick at least one.
  </Step>

  <Step title="Copy your credentials">
    Your **client ID** (and, for a confidential app, the **client secret**) is shown once. Copy the secret now. You won't see it again, and regenerating it invalidates the old one immediately.
  </Step>
</Steps>

## Client id and secret rotation

From the app's edit page, under **Danger zone**:

* **Regenerate secret** (confidential apps only): issues a new client secret and immediately invalidates the old one. Every server using it must be updated before it works again.
* **Delete app**: permanently deletes the app, revokes every user's authorization, and invalidates all issued tokens. This can't be undone.

## Scopes

Your app's registration sets the **ceiling**: the most it can ever request. An authorization request can ask for that full set or a narrower one; the user approves exactly what's requested.

| Scope               | Grants                                           | Resource    |
| ------------------- | ------------------------------------------------ | ----------- |
| `apps:read`         | See your published flows and their input schemas | Flows       |
| `runs:read`         | See your runs and their results                  | Runs        |
| `runs:write`        | Run your flows (uses your credits)               | Runs        |
| `generations:read`  | See your generations and their outputs           | Generations |
| `generations:write` | Generate images and videos (uses your credits)   | Generations |
| `assets:read`       | Browse and download your assets                  | Assets      |
| `credits:read`      | See your credit balance                          | Credits     |
| `elements:read`     | See your reusable elements                       | Elements    |
| `elements:write`    | Create reusable elements                         | Elements    |

<Note>
  **Write implies read** in the consent display: if your app requests both `generations:read` and `generations:write`, the consent screen shows only the `generations:write` sentence. A write scope is treated as a superset of its read sibling. Request the read scope alone if your app only ever reads.
</Note>

<Warning>
  Any **write** scope (`runs:write`, `generations:write`, `elements:write`) spends the connected user's **own credits** when your app uses it. The same as if they'd triggered it from the dashboard. Ask for only the write scopes your integration actually needs.
</Warning>

## The consent screen

When a user authorizes your app, they see:

* Your app's **logo and name**, "*Your app* wants to access your Flowy account", linking to your website if you set one.
* A bullet list built from each requested scope's **consent sentence** (the "Grants" column above): e.g. "Generate images and videos (uses your credits)".
* **Authorizing as**: the signed-in user's name, avatar, and email, with a **Switch account** link if they want to authorize as someone else.
* **Decline** / **Authorize** buttons.

The resulting grant is **account-bound**: it isn't scoped to a single workspace the user picks on this screen. Once connected, your app acts in the user's personal account wallet by default, or in any workspace the account can manage by sending a `workspace_id` on the underlying `/v1` call: the same OAuth-connection model [Authentication](/api/authentication) describes.

## Connected apps and revocation

Users manage every app they've authorized from [Settings → Connected apps](/settings/connected-apps): a table of **App**, **Access** (the granted scopes), **Authorized** date, and **Last used**. Selecting **Disconnect** on a row revokes that authorization immediately: your app's access token stops working and its tokens are invalidated. The user can reconnect later by authorizing again from your app.

<Tip>
  If your integration needs the full account surface rather than the scoped `/v1` API (for a native client, for example), see [Create a session](/api/create-session) for the token-for-session exchange, and read its privilege-escalation warning first.
</Tip>
