# Sign-in and permissions

> Scoped API keys, OAuth 2.1 for MCP clients, every permission and how a client asks for more.

Source: https://app.poacher.io/developers/authorization · API version 1.10.1

Every key and token belongs to one Poacher account, carries only the permissions the person ticked and expires after 7, 30 or 90 days. The person can see and revoke each one in [Developer access](https://app.poacher.io/account/developer).

## Permissions {#permissions}

| Permission | Allows | On the consent screen |
| --- | --- | --- |
| `account:read` | Read balances, monthly cap and billing environment. | Ticked |
| `alerts:read` | Read alerts and their saved settings. | Ticked |
| `results:read` | Read matching results. | Ticked |
| `alerts:write` | Rename and pause alerts. | Unticked: the person must choose it |
| `work:execute` | Quote and run approved paid previews and one-off checks. | Unticked: the person must choose it |
| `channels:manage` | Add and confirm channels; choose where an alert sends results. | Unticked: the person must choose it |

A key never includes another customer’s data or administrator access. Billing settings cannot be changed through the API.

## Keys {#keys}

Create a key in [Developer access](https://app.poacher.io/account/developer) and send it as `Authorization: Bearer poacher_v1_…`. Creating or revoking a key needs a sign-in from the last ten minutes. An account can have ten active keys.

## OAuth for MCP clients {#oauth}

MCP clients sign in with OAuth 2.1, so nobody pastes a key. The access token is an ordinary scoped Poacher key.

- **Protected resource:** `https://app.poacher.io/mcp` ([metadata](https://app.poacher.io/.well-known/oauth-protected-resource/mcp))
- **Authorization server:** `https://app.poacher.io` ([metadata](https://app.poacher.io/.well-known/oauth-authorization-server))
- **Grant:** authorization code with PKCE (S256); public clients only
- **Client registration:** client ID metadata documents, or dynamic registration at `/api/oauth/register`
- **Tokens:** 7, 30 or 90 days, chosen by the person; no refresh tokens

1. The client calls a tool and gets HTTP 401 with `WWW-Authenticate: Bearer resource_metadata="…", scope="…"`.
2. It reads the protected-resource and authorization-server metadata, then sends the person to `/oauth/authorize`.
3. The person signs in, sees which app is asking and where it will return, and ticks the permissions to allow. Writes and spending start unticked.
4. Poacher redirects back with a code and `iss`; the client exchanges the code at `/api/oauth/token`.

Redirect addresses must be HTTPS, loopback HTTP (`http://127.0.0.1` or `http://localhost`, any port) or an app’s own scheme such as `cursor://`. Connecting the same app again replaces its earlier key. Replaying a code revokes the key it produced.

## Asking for more permission {#step-up}

When a signed-in client calls a tool its token cannot use, `/mcp` answers HTTP 403:

```http
WWW-Authenticate: Bearer resource_metadata="https://app.poacher.io/.well-known/oauth-protected-resource/mcp", error="insufficient_scope", scope="alerts:read results:read"
```

`scope` lists everything the client should ask for: what it has and what it needs. The REST API answers the same way with `required_scope` in the error body.
