# Authentication

_Last updated: August 21, 2026_

Waydock's MCP server accepts two credentials: **OAuth 2.1** access tokens, for MCP clients that support one-click connect, and **per-user bearer API keys**, for scripts and self-hosted automation. Both are checked at the same endpoint and carry the same scope catalog, and every call is audited either way. New here? Start with the [Quickstart](/docs/quickstart).

> **For agents:** the machine-readable version of this page is [/auth.md](/auth.md). To connect over OAuth, fetch `/.well-known/oauth-protected-resource` (an unauthenticated call to the MCP endpoint returns it in the `WWW-Authenticate` challenge) and follow the flow. To use a key instead, send `Authorization: Bearer wdmcp_...` on every request to `https://mcp.waydock.ai/mcp`.

## Connecting over OAuth 2.1

Waydock runs its own authorization server for MCP, so a client can connect without the user ever handling a secret. Authorization code flow with PKCE (S256 required), public clients supported, and dynamic client registration is open, which is what makes one-click connect work in Claude, ChatGPT, VS Code, and Cursor.

The flow, in order:

1. **Register.** `POST /api/oauth/register` (RFC 7591) with your client metadata, and get a `client_id` back.
2. **Authorize.** Send the user to `/oauth/authorize`. They see a consent screen naming your client and the exact permissions asked for, with anything that can reach another person spelled out on its own line. Consent is **not** all-or-nothing: the write row and the send-on-your-behalf row are checkboxes (read is required), and the user grants only what they leave ticked. Both arrive ticked, so approving is one click. That is a looser default than the `full-access` API-key preset, where third-party send (`write:mail.send`, `write:teams.send`) is always a separate opt-in. A closed **Limit to specific areas** control below the rows lets the user share only some parts of Waydock (say, Pulse monitoring) even when you asked for the whole catalog, so ask for only the scopes you need. On approval you get a single-use code, valid for two minutes.
3. **Exchange.** `POST /api/oauth/token` with the code and your PKCE verifier. The token response's `scope` field is authoritative: **read it**, because the user may have granted less than you asked for. Access tokens (`wdat_`) last one hour; refresh tokens (`wdrt_`) last 30 days and rotate on every use.
4. **Call.** Send `Authorization: Bearer wdat_...` to the MCP endpoint, refreshing before the hour is up.

**Do not paste a `wdat_` token into a config file.** An `Authorization` header written into an `mcpServers` entry is not an OAuth client: nothing there refreshes, so the connection dies within the hour. If your client cannot store and refresh tokens, and its config holds only static headers, use an API key instead. It is long-lived, revocable, and carries the same scopes.

Tokens are audience-bound to the server URL they were requested for (`https://mcp.waydock.ai/mcp`, or the earlier `https://waydock.ai/api/mcp/stream` for connections made before the dedicated host existed), so a token minted for Waydock's MCP server cannot be replayed at another resource.

Either side can end the connection. A client calls `POST /api/oauth/revoke` (RFC 7009), which kills the whole grant rather than the single token presented. The user sees every connected app under **Settings → Account → MCP**, with the scopes it holds and a one-click revoke.

The rest of this page covers the API-key path.

## The key

A Waydock MCP key looks like this:

```text
wdmcp_a1b2c3d4_9f8e7d6c5b4a39281706f5e4d3c2b1a0
```

The `wdmcp_` prefix, a short public segment, and a long random secret. The key is shown **once** at creation. Waydock stores only a SHA-256 hash of it, never the key itself, and verifies with a constant-time comparison.

## Issuing a key

1. Sign in and open **Settings → Account → MCP** ([/settings/account/mcp](/settings/account/mcp)).
2. Click **Create key** and choose a scope preset (**Read & message myself** or **Full access**) or a custom scope set. See [Scopes & presets](/docs/tools#the-scope-catalog).
3. Name the key after the agent that will use it (for example `claude-desktop`, `cursor`, `nightly-brief-bot`). The name appears in your audit log next to every call.
4. Copy the key. It is not shown again.

You can hold up to **3 live keys on Free** and **5 on Pro**. New keys are read-only by default.

## Sending the key

Pass the key as a bearer token on every MCP request:

```text
Authorization: Bearer wdmcp_xxxxxxxx
```

The `X-API-Key: wdmcp_xxxxxxxx` header is also accepted. Keys created before a past rename may start with the legacy `ddmcp_` prefix; those still authenticate.

## Optional restrictions per key

Each key can be locked down further, all enforced at authentication time:

- **Expiry.** Set an expiry date; the key stops authenticating the moment it passes.
- **IP allowlist.** Restrict a key to one or more CIDR ranges. A call from an address outside the list is rejected before any tool runs.
- **Tool denylist.** Block specific tools for a key regardless of its scopes. Useful to hand an agent broad read scopes but withhold, say, `waydock_send_email`.

## Lifecycle

- **Rotate.** Generate a fresh secret for an existing key without changing its id or scopes. The old secret stops working immediately, and the new one is shown once. Use this if a key may have leaked.
- **Revoke.** Delete a key instantly. Because the app UI and the MCP endpoint read the same key record, revoking stops both in the same moment.
- **History.** Every key keeps a change log (create, update, rotate, revoke, re-consent), and every call is written to the audit log with the agent name, tool, outcome, and latency.

## Re-consent when scopes are added

Each key is stamped with the scope **catalog version** it was created under. When Waydock adds new optional scopes to the catalog, an existing key does **not** silently gain them. The key is flagged as pending re-consent, and the owner explicitly acknowledges the new version to pick up any new scopes they want. Existing grants are never changed without the owner's action.

## Rate limits and idempotency

- **Daily call ceiling** follows the plan: **500 per day on Free, 25,000 on Pro**, plus a per-IP window. Call `waydock_quota` (no scope required) for your remaining budget.
- **Idempotency.** Send an `Idempotency-Key` header (or `X-Idempotency-Key`) on a write request and Waydock returns the cached response for a repeat of the same key, so a retried send does not fire twice.

## Discovery endpoints

| Endpoint | Auth | Purpose |
| --- | --- | --- |
| `GET /.well-known/mcp/server-card.json` | public | Server discovery card |
| `GET /.well-known/oauth-protected-resource` | public | Protected resource metadata (RFC 9728) |
| `GET /.well-known/oauth-authorization-server` | public | Authorization server metadata (RFC 8414) |
| `GET /api/mcp/manifest` | public | Full tool + scope catalog |
| `GET /auth.md` | public | This authentication guide, as Markdown |
| `GET /api/mcp/health` | key | Liveness |
| `GET /api/mcp/whoami` · `/me` · `/limits` | key | Identity, key details, budget |

## Security properties

- Keys are stored as a **SHA-256 hash**, never in plaintext, and compared in constant time.
- Outbound send is **wildcard-proof**: a key cannot send to third parties unless its scope list contains the literal `write:mail.send`. No preset or wildcard satisfies it.
- Every call is scope-checked and, for paid write scopes, entitlement-checked at call time.
- All access is logged to one audit trail shared by the app and the agent endpoint.

## See also

- [Quickstart](/docs/quickstart) for client configs
- [Tool reference](/docs/tools) for tools, scopes, and presets
- [Security](/security) for the outbound-safety contract
