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

# Authentication

> How to authenticate to Peel and how session-based target-site calls work.

Peel has two separate auth layers:

* **Host auth:** who is allowed to call Peel.
* **Target-site session auth (`session_required`):** credentials some compiled endpoints need for the target site.

The CLI uses the same host auth model, then stores the resulting API key locally for later REST and MCP calls.

## Host auth to call Peel

For external REST usage, authenticate to Peel with `X-API-Key`:

<CodeGroup>
  ```bash cURL theme={null}
  curl -H "X-API-Key: $PEEL_API_KEY" "$PEEL_API_BASE/v1/apis"
  ```

  ```javascript Node.js theme={null}
  const res = await fetch(`${process.env.PEEL_API_BASE}/v1/apis`, {
    headers: { "X-API-Key": process.env.PEEL_API_KEY },
  });
  ```

  ```python Python theme={null}
  import os, requests

  res = requests.get(
      f"{os.environ['PEEL_API_BASE']}/v1/apis",
      headers={"X-API-Key": os.environ["PEEL_API_KEY"]},
  )
  ```
</CodeGroup>

`X-API-Key` identifies the Peel actor that owns the API, is billed for calls, and can revise or rebuild it.

Public `/v1/apis/...` routes can also be called from the first-party app with session auth, but that is a host-side app session, not target-site auth.

## CLI auth

The CLI defaults to `https://api.peel.sh` for API requests and supports two host-auth paths:

* `peel auth login` for browser device flow
* `peel auth login --api-key ...` for direct key injection

The OpenAPI bundle includes the CLI-facing device helpers, `POST /public/device/start` and `POST /public/device/exchange`. The signed-in browser approval step is handled by the first-party Peel app.

```bash theme={null}
peel auth login
peel auth login --api-key sk_...
peel auth status
peel auth logout
```

`peel setup` wraps this flow and then continues with MCP install plus doctor checks.

### Headless signup

If the target deployment allows public signup, the CLI also supports:

```bash theme={null}
peel auth signup --email you@example.com --password 'secret123'
```

If signup is disabled, the command fails cleanly and tells you to use an existing account instead.

<Info>
  On `peel.sh`, public signup is disabled during private preview. Use an existing account, then create API keys from [settings](https://peel.sh/settings). Headless signup only applies to deployments where an operator enabled public signup.
</Info>

## MCP auth

`/mcp` accepts either:

* `X-API-Key`
* `Authorization: Bearer ...` for MCP OAuth clients

```json theme={null}
{
  "mcpServers": {
    "peel": {
      "url": "https://api.peel.sh/mcp",
      "headers": {
        "X-API-Key": "YOUR_PEEL_API_KEY"
      }
    }
  }
}
```

OAuth bearer tokens authenticate to the Peel host only. They do not replace `session_id` and `encryption_key` for protected target-site endpoints.

## `session_required` is a second layer

Some compiled APIs publish a deterministic login endpoint and one or more protected endpoints.

* The login endpoint returns `session_id`, `encryption_key`, and `initiates_session: true`.
* Protected endpoints require both values on every call.

This layer authenticates to the target site. It does not authenticate you to Peel itself.

## REST session credentials

For `POST /v1/apis/{api_id}/endpoints/{endpoint_name}:call`, runtime accepts session credentials in either place:

* Preferred headers: `X-Session-ID` and `X-Encryption-Key`
* Request body fields: `session_id` and `encryption_key`

Headers win if both are present.

```bash theme={null}
curl -X POST "$PEEL_API_BASE/v1/apis/$API_ID/endpoints/login:call" \
  -H "X-API-Key: $PEEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"***"}'
```

```bash theme={null}
curl -X POST "$PEEL_API_BASE/v1/apis/$API_ID/endpoints/inbox:call" \
  -H "X-API-Key: $PEEL_API_KEY" \
  -H "X-Session-ID: SESSION_ID" \
  -H "X-Encryption-Key: ENCRYPTION_KEY" \
  -H "Content-Type: application/json" \
  -d '{"folder":"inbox"}'
```

## MCP session credentials

`call_endpoint` takes session credentials as top-level tool arguments, with endpoint params nested under `params`. The shape below is the `arguments` object inside a JSON-RPC `tools/call` request. See [Authenticated APIs](/features/authenticated-apis#mcp-shape) for the full envelope.

```json theme={null}
{
  "name": "call_endpoint",
  "arguments": {
    "api_id": "550e8400-e29b-41d4-a716-446655440000",
    "endpoint_name": "inbox",
    "session_id": "SESSION_ID",
    "encryption_key": "ENCRYPTION_KEY",
    "params": {
      "folder": "inbox"
    }
  }
}
```

## Production guidance

* Treat `X-API-Key` as the primary deployment secret. Rotate it with your normal secret-management process.
* Keep session values (`session_id`, `encryption_key`) transient. Do not persist them outside your trusted runtime.
* If a site cannot be reduced to a compiled login plus deterministic protected calls, it is not a supported `session_required` surface.

## Calling Peel from a browser

`api.peel.sh` runs with a strict CORS allowlist. By default, only the Peel SPA at `https://peel.sh` is allowed, with credentials. Arbitrary third-party origins are rejected.

Two rules of thumb:

* **Never ship `X-API-Key` in client-side JavaScript.** Keys are deployment secrets. Call Peel from your server and expose a scoped proxy route to your frontend.
* **If you need browser-to-Peel calls from your own origin**, email [kaan@peel.sh](mailto:kaan@peel.sh) to get your domain added to the allowlist. This is a one-off configuration change, not a self-service setting.
