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

# Authentication

> How the Moda MCP server authenticates users via OAuth 2.1 and Clerk.

The hosted MCP server at `mcp.moda.app/mcp` supports **two authentication methods**. Pick whichever matches how you'll be invoking it.

## Which method should I use?

### OAuth 2.1 — pick this when a human is driving

**Use cases**

* **Claude Desktop / claude.ai**: everyday design work by you or your team.
* **Cursor / VS Code**: a developer translating Moda designs to code, or generating UI.
* **Claude Code on your laptop**: ad-hoc canvas queries from the terminal.
* **Claude mobile**: carry-over of your desktop connector.

**How it works.** On first use, your client pops a browser, you sign in to Moda (via Clerk), and tokens get stored by the client. Every subsequent tool call is authenticated silently — you won't see the sign-in again unless your session expires or you revoke access. Individual team members see their own canvases, orgs, and credits.

**What you get.** Per-user identity. Every tool call runs as *you*; `list_my_canvases` returns the canvases you personally have access to, design tasks bill against your team's credits, and audit logs attribute actions to your user.

### API key — pick this when there's no human in the loop

**Use cases**

* **Scheduled content generation.** Daily social post at 9am? Weekly carousel? There's no human to click a consent screen — the job needs a durable credential.
* **Claude Managed Agents.** Anthropic's platform-managed agents can run on a cron. They need a bearer token, not an OAuth flow.
* **CI/CD pipelines.** Regenerating branded assets on merge to main, or running design smoke tests in GitHub Actions.
* **Server-side integrations.** Your backend code calling the MCP directly (rather than wrapping the REST API) — a bot that drafts design tasks from a Slack command, or a webhook handler that kicks off tasks.
* **Internal tools your team uses across many sessions.** Some teams prefer a stable, rotatable credential per integration instead of managing individual OAuth sessions per teammate.

**How it works.** Generate a key in **Settings → Developer → REST API**, then configure your MCP client to send `Authorization: Bearer moda_live_...`. The key ties every tool call to the team it was created under.

**What you get.** Team-level identity. Every call runs as the key's owner + team.

### Rules of thumb

| Situation                                                        | Use                                                               |
| ---------------------------------------------------------------- | ----------------------------------------------------------------- |
| "A person is clicking something and will see the result in chat" | **OAuth**                                                         |
| "A scheduled job runs at 3am"                                    | **API key**                                                       |
| "Different teammates each connect their own editor"              | **OAuth** (each person signs in as themselves)                    |
| "One service account drives a pipeline"                          | **API key**                                                       |
| "I need to rotate credentials regularly"                         | **API key** (revoke + regenerate in Settings; no end-user impact) |
| "I need the simplest possible setup"                             | **OAuth** (no key management)                                     |

### Mixing both

The server accepts both methods simultaneously — you can have your own Cursor connected via OAuth, and a Claude Managed Agent connected with an API key, against the same Moda account. They don't conflict; pick the right auth for each caller.

## When is authentication required?

| Action                                             | Auth required |
| -------------------------------------------------- | ------------- |
| Fetch a **public** share link (`moda.app/s/...`)   | No            |
| Fetch a **private** canvas (`moda.app/canvas/...`) | Yes           |
| List your canvases                                 | Yes           |
| Search your canvases                               | Yes           |

Public share links work without authentication in both local and remote server modes. Private canvases and canvas listing/searching require the remote server with either OAuth or an API key.

## Setting up API-key auth

### 1. Generate a key

In your Moda account, go to **Settings → Developer → REST API → Create API key**.

Copy the `moda_live_...` key — **it's shown once**. Store it in a secret manager.

### 2. Configure your client

<Tabs>
  <Tab title="Claude Code">
    ```bash theme={null}
    claude mcp add moda https://mcp.moda.app/mcp \
      --transport http \
      --scope user \
      --header "Authorization: Bearer moda_live_..."
    ```

    The URL must come immediately after the server name; `--header` uses an HTTP-style `Name: value` format with a colon, not `=`.

    `--scope user` keeps the key in your per-user Claude config rather than a repo-level file that could get committed.
  </Tab>

  <Tab title="Cursor">
    Edit `~/.cursor/mcp.json` (or project-level `.cursor/mcp.json`):

    ```json theme={null}
    {
      "mcpServers": {
        "moda": {
          "type": "streamable-http",
          "url": "https://mcp.moda.app/mcp",
          "headers": {
            "Authorization": "Bearer moda_live_..."
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="VS Code">
    In user or workspace `settings.json`:

    ```json theme={null}
    {
      "mcp": {
        "servers": {
          "moda": {
            "type": "streamable-http",
            "url": "https://mcp.moda.app/mcp",
            "headers": {
              "Authorization": "Bearer moda_live_..."
            }
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="curl / scripts">
    Any HTTP client can connect directly — useful for CI, smoke tests, or custom integrations:

    ```bash theme={null}
    curl -X POST https://mcp.moda.app/mcp \
      -H "Authorization: Bearer $MODA_API_KEY" \
      -H "Accept: application/json, text/event-stream" \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
    ```
  </Tab>
</Tabs>

<Info>
  **Claude Desktop and claude.ai don't support custom headers** in their connector UI today — they assume OAuth for
  remote MCPs. Use OAuth for Claude Desktop; reserve API keys for Cursor / VS Code / Claude Code / CLI / cron.
</Info>

### 3. Identity

Every tool call authenticated with an API key runs as the **key's owner + team**. `list_my_canvases` returns the key-owner's canvases; `start_design_task` bills their team's credits. Session context (`set_context`) persists per-user across calls, same as OAuth — different keys mean different owners, so multi-tenant reuse is safe.

### 4. Rotating or revoking a key

Go to **Settings → Developer → REST API**, revoke the key, and generate a new one. Update the bearer token in your MCP client config. No coordination with end-users needed — API keys are meant to rotate.

## How the OAuth flow works

When you first use the MCP server, your editor initiates the OAuth flow:

1. Your editor sends a request to the MCP server
2. The server responds with `401 Unauthorized`
3. Your editor discovers the OAuth endpoints automatically
4. A browser window opens for you to sign in via Moda (powered by Clerk)
5. After sign-in, tokens are exchanged and stored by your editor
6. All subsequent requests are authenticated automatically

If you're already signed in to [moda.app](https://moda.app) in your browser, the sign-in step is instant — your existing session is detected automatically.

## Token lifecycle

| Token         | Lifetime | Notes                                  |
| ------------- | -------- | -------------------------------------- |
| Access token  | 24 hours | Refreshed automatically by your editor |
| Refresh token | 30 days  | Rotated on each use for security       |

Your editor manages token refresh transparently. You should rarely need to re-authenticate unless you revoke access or your refresh token expires.

## Local server authentication

The local `stdio` server does not use authentication. It can only access **public** share links. To access private canvases, use the remote server at `mcp.moda.app`.

## Revoking access

**OAuth sessions** — remove the connector in the client:

* **Claude Desktop / claude.ai**: **Settings > Connectors** → disconnect or remove the Moda connector.
* **Claude Mobile**: Disconnect the Moda connector from [claude.ai/settings](https://claude.ai/settings), then restart the mobile app.
* **Claude Code**: `claude mcp remove moda`.
* **Cursor**: Remove the server from Cursor Settings > MCP.
* **VS Code**: Remove the Moda entry from your MCP `settings.json`.

This removes the stored tokens locally. You'll re-authenticate on next connect.

**API keys** — revoke the key itself at **Settings → Developer → REST API**. Every client using that key loses access immediately across all sessions and devices. Generate a fresh key and update your client config to continue.

## Security

* OAuth 2.1 with PKCE (Proof Key for Code Exchange) prevents authorization code interception.
* OAuth access tokens are short-lived JWTs (24 hours); refresh tokens are rotated on each use.
* API keys are hashed at rest; only the `moda_live_` prefix is logged for debugging. Lose a key? Revoke it in **Settings → Developer**.
* A compromised or prompt-injected MCP call can't use the key to rotate webhooks or read raw credit balances — MCP-originated requests are restricted to a safe subset of operations regardless of what the key itself allows at the REST layer.
* All communication with `mcp.moda.app` uses TLS.
* The MCP server never stores your Moda password — OAuth authentication is delegated to Clerk.
