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

# Authentication

> OAuth 2.1 with PKCE, dynamic client registration, and scope enforcement.

The MCP endpoint authenticates via **OAuth 2.1** — the same standard used by
Claude Desktop, claude.ai, and most MCP clients. There's no API key to manage:
the user authorizes a client once and the client receives short-lived access
tokens that it refreshes automatically.

## Discovery

MCP-compatible clients automatically discover the authorization server via the
RFC 8414 metadata document:

```
GET https://api.propal.io/v1/.well-known/oauth-authorization-server
```

The response advertises:

* `authorization_endpoint` — where the user grants consent
* `token_endpoint` — where clients exchange codes / refresh tokens
* `registration_endpoint` — RFC 7591 Dynamic Client Registration (no manual
  setup needed)
* Supported scopes, grant types, PKCE methods (S256 mandatory), and signing
  algorithms

You don't normally interact with this endpoint manually — your MCP client does
it for you.

## The flow

<Steps>
  <Step title="Client registration (one-time, automatic)">
    On first connection, your MCP client posts to the registration endpoint
    and receives a `client_id`. No human action required.
  </Step>

  <Step title="Authorization request">
    The client opens a Propal-hosted consent page in the user's browser, with
    a PKCE challenge. The user is asked to log in (if not already), pick the
    organization to grant access to, and confirm the scopes requested.
  </Step>

  <Step title="Code exchange">
    Once consent is granted, Propal redirects to the client with an
    authorization code. The client exchanges it for a short-lived access
    token + a refresh token, sending the PKCE verifier.
  </Step>

  <Step title="Authenticated calls">
    Every MCP call carries the access token as `Authorization: Bearer <token>`.
    The token includes the user's identity and the organization context.
  </Step>

  <Step title="Refresh">
    When the access token expires, the client uses the refresh token silently
    — no user prompt.
  </Step>
</Steps>

## The `mcp:use` scope

Every MCP call requires the `mcp:use` scope. This is granted by default when
the user authorizes a client. Without it, you'll get:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "error": {
    "code": "forbidden",
    "message": "Missing required scope: mcp:use"
  }
}
```

Inside the MCP server, individual tool authorization derives from the user's
membership in the organization (RLS in Supabase). You don't manage per-tool
scopes — if the user can do it in the Propal app, the MCP can do it too.

## Organization context

The MCP is scoped to a **single organization per session**. When the user
consents, they pick which organization to grant access to. All subsequent
calls operate inside that organization — there's no cross-org access.

To switch organizations, the user re-authorizes the client (most clients
expose a "Reconnect" or "Sign in again" action).

## Revoking access

Users revoke connectors from **Settings → Integrations** in the Propal app.
After revocation, the client's refresh token is invalidated — the next API
call returns `401 Unauthorized` and the client can re-trigger the OAuth flow.

## Security notes

* **PKCE S256 is mandatory** for all clients. We reject `plain` PKCE.
* **Tokens are short-lived** (1h access, 30d refresh). Refresh tokens rotate
  on each use.
* **No client secrets** are issued — Dynamic Client Registration produces
  public clients with PKCE binding.
* **Organization scoping is enforced server-side** at every tool call. The
  token alone doesn't grant access; the user's membership is re-checked.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The browser doesn't open during authorization">
    Most MCP clients shell out to the OS browser. If yours doesn't, copy the
    URL from the client logs and open it manually.
  </Accordion>

  <Accordion title="&#x22;invalid_grant&#x22; on token refresh">
    The refresh token has been revoked (the user disconnected the client) or
    expired (>30 days). Re-trigger the OAuth flow.
  </Accordion>

  <Accordion title="&#x22;forbidden — missing scope: mcp:use&#x22;">
    The client requested fewer scopes than required. Reconnect with the
    default scope set; the user will be re-prompted to consent.
  </Accordion>

  <Accordion title="claude.ai shows a 'Connection failed' state">
    The most common cause is a server discovery glitch — wait 30s and click
    'Retry'. If it persists, check that
    `https://api.propal.io/v1/.well-known/oauth-authorization-server`
    returns `200`.
  </Accordion>

  <Accordion title="ChatGPT can't add the connector ('not supported on your plan')">
    Custom MCP connectors require a Plus, Pro, Team, or Enterprise plan.
    Free accounts can use the public REST API instead — see the
    [API quickstart](/api-reference/quickstart).
  </Accordion>

  <Accordion title="Codex / IDE refuses to open the browser">
    Headless or CI environments often can't pop a browser. Run an
    interactive `codex` (or IDE) session once on a machine with a browser to
    complete the OAuth flow — the refresh token is cached locally
    (`~/.mcp-auth/` for `mcp-remote`, `~/.codex/auth/` for Codex) and reused
    silently afterwards.
  </Accordion>

  <Accordion title="Tools appear without a 'propal_' prefix">
    Some clients (notably Codex CLI) prefix tool names with the connector
    name, e.g. `propal__list_propal_components`. Others (Claude Desktop,
    ChatGPT) keep the original name. The behavior is fully client-side —
    the MCP server registers them as `list_propal_components`, etc.
  </Accordion>
</AccordionGroup>
