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

# OAuth Apps

> Scoped, user-delegated access through a registered OAuth 2.1 application

An OAuth application acts **on behalf of a specific user**. It holds an access token that carries
only the scopes that user consented to, and every call it makes is evaluated against that user's own
permissions in Chamelio. If the user cannot open a task in the web application, the application
cannot read it through the API either.

Chamelio implements OAuth 2.1 with PKCE. Tokens are opaque bearer tokens.

## Base URL

```
https://platform.chamelio.ai/v2
```

The authorization server itself lives one level up, at `https://platform.chamelio.ai/oauth/...`.

## Authentication

Send the access token as a bearer token:

```bash theme={null}
Authorization: Bearer your_access_token
```

<Warning>
  These endpoints accept bearer tokens only. Sending an `X-API-Key` header to a `/v2` path returns
  `401 Unauthorized` - the API key surface is documented under
  [API Keys](/api-reference/api-keys).
</Warning>

## How it works

<Steps>
  <Step title="Register an application">
    An organization admin registers the application in
    [Developer settings](https://app.chamelio.ai/b/settings/developer?developerTab=applications) and
    chooses the scopes it may ever request. This yields a `client_id`, and for confidential clients a
    `client_secret` shown only once. See
    [Managing Applications](/api-reference/oauth/applications).
  </Step>

  <Step title="Send the user to consent">
    Redirect the user to [`/oauth/authorize`](/api-reference/oauth/authorize) with a PKCE challenge.
    They review the requested scopes and approve, and you receive a single-use authorization code.
  </Step>

  <Step title="Exchange the code for a token">
    Call [`/oauth/token`](/api-reference/oauth/token) with the code and your PKCE verifier to get an
    access token.
  </Step>

  <Step title="Call the API">
    Use the token against `/v2` endpoints. Each endpoint states the scope it requires.
  </Step>
</Steps>

## Scopes

Scopes follow the `resource:action` convention and are requested as a space-delimited string.

| Scope             | Grants                                           |
| ----------------- | ------------------------------------------------ |
| `workflows:read`  | List and read workflows and their status         |
| `workflows:write` | Initiate and act on workflows                    |
| `tasks:read`      | Read tasks                                       |
| `tasks:write`     | Create and modify tasks                          |
| `files:read`      | Download files                                   |
| `users:read`      | Read organization users and groups               |
| `users:write`     | Create and modify organization users and groups  |
| `sor:read`        | Read system-of-record objects                    |
| `sor:write`       | Write system-of-record objects                   |
| `clickwrap:read`  | Read clickwrap agreements and acceptance records |
| `clickwrap:write` | Record clickwrap acceptance events               |

<Warning>
  `:write` does **not** imply `:read`. An application that both reads and writes tasks must request
  `tasks:read tasks:write`.
</Warning>

<Info>
  An application's `allowed_scopes` may accept `documents:read`, `documents:write`, `files:write` and
  `mcp:read` as well. Those are reserved for endpoints that do not exist yet and grant nothing today -
  requesting them has no effect. Every scope enforced by a live endpoint is listed in the table above.
</Info>

Note that some task endpoints are gated on `files:read` rather than `tasks:read`, because they
return file content: listing a task's files, downloading a step document, and retrieving signed
documents. Each endpoint page states its own required scope.

## Acting as a user

Every `/v2` call runs as the user the token was issued to. Two consequences:

* **Permissions are enforced per resource.** Reaching a task, workflow, or file the user has no
  access to returns `403 Forbidden`, regardless of scope.
* **Writes are attributed to that user.** Comments are posted as them, tasks are initiated as them,
  and users or groups they create are recorded as created by them. Request body fields that name a
  different actor - `user_email` on task endpoints, `user` on workflow initiation - are ignored.

The one exception is `/v2/server/clickwrap/*`. The subject of a clickwrap event is `user_identifier`,
an opaque string you supply for *your own* end user, which is never resolved against Chamelio's users.
Those four endpoints are therefore authorized by organization and scope alone, with no acting user.

### Client credentials tokens

A `client_credentials` token acts as the admin who created the application, so it can call `/v2`
like any other token. Calls are attributed to that admin, and the resources the token can reach are
the ones that admin can reach.

<Warning>
  Whoever creates a `client_credentials` application decides what its tokens can see. Create the
  application as a user whose access matches what the integration actually needs, and remember that
  deactivating that user revokes its tokens - see [403 Forbidden](#403-forbidden) below.
</Warning>

Tokens issued before application creators were recorded have no user behind them. Those predate the
change and are rejected on any `/v2` endpoint that acts as a user; request a new token to replace one:

```json theme={null}
{
  "detail": "client_credentials tokens are not associated with a user"
}
```

## Token lifetime

Access tokens do **not** expire by default. An application can opt into a finite lifetime by setting
`default_token_ttl_seconds` at registration, and only then is a refresh token issued alongside the
access token. Refreshing rotates the pair: the old access and refresh tokens are both revoked.

`client_credentials` never receives a refresh token - request a new one instead.

Tokens can be revoked individually with [`/oauth/revoke`](/api-reference/oauth/revoke), and deleting
an application revokes every token it ever issued.

## Rate limiting

OAuth traffic is rate limited **per organization**, not per token, using a one-minute window. An
application may hold many tokens, so the organization is the meaningful unit to throttle.

Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. Exceeding the
limit returns `429 Too Many Requests` with a `Retry-After` header.

## Error responses

Every `/v2` endpoint can return the following. Individual pages document the errors specific to them.

### 401 Unauthorized

The token is missing, unknown, revoked, or expired - or an `X-API-Key` was sent instead of a bearer
token. Responses carry `WWW-Authenticate: Bearer`.

```json theme={null}
{
  "detail": "Invalid access token"
}
```

### 403 Forbidden

Either the token lacks a required scope:

```json theme={null}
{
  "detail": "Insufficient scope; this endpoint requires: tasks:write"
}
```

Or the user may not reach the resource:

```json theme={null}
{
  "detail": "You do not have access to this resource"
}
```

Or the user the token acts as is no longer an active member of the organization:

```json theme={null}
{
  "detail": "Token owner is inactive or not found"
}
```

<Warning>
  That last case **revokes the token**. Deactivating a user permanently invalidates every access
  token issued to them, including `client_credentials` tokens for applications they created.
  Reactivating the user does not bring the tokens back - issue new ones.
</Warning>

### 404 Not Found

```json theme={null}
{
  "detail": "Not found"
}
```

### 422 Unprocessable Entity

The request body failed validation, or the operation was rejected for the state it was in. The
`detail` is either FastAPI's field-level error array or a specific message describing what to fix.

<Info>
  `403` and `404` bodies are intentionally generic. The underlying reason is recorded in Chamelio's
  logs rather than returned, so responses cannot be used to probe for resources the user cannot see.
</Info>

## Next steps

<Columns cols={2}>
  <Card title="Get an Access Token" icon="key" href="/api-reference/oauth/token">
    The three supported grants and their parameters
  </Card>

  <Card title="Authorize a User" icon="user-check" href="/api-reference/oauth/authorize">
    Start the authorization code flow with PKCE
  </Card>

  <Card title="Managing Applications" icon="gear" href="/api-reference/oauth/applications">
    Register an application and configure its scopes and redirect URIs
  </Card>

  <Card title="Get Current User" icon="id-card" href="/api-reference/endpoint/v2/users/user-info">
    Confirm which user and scopes a token resolves to
  </Card>
</Columns>
