# API authentication

Choose OAuth or a scoped environment-secret handoff according to the client and API surface.

- Canonical: https://docs.xmemo.dev/docs/api/authentication
- Locale: en-US
- Content-Locale: en-US
- Canonical-Content-Digest: bf8cd5a2198df98cbe1762a320a10c3f6af876a5d87dc2d0071accba4274942a
- Edition-Digest: 2c338534c1006249c0e6c739b3e621f9a4aa23ff63d05fa0bacacbf4d2482289
- Source-Revision: sha256:31434f9554ada1554305cf18e547a0ac8d645dbc304ddbe0d2a12d5bfd990665

## Two authenticated surfaces

The hosted MCP endpoint and the REST API authenticate differently. Pick the one that matches the client you are wiring, and never place a credential in public configuration or a generated URL.

- MCP — OAuth where the client supports it, otherwise Authorization: Bearer ${XMEMO_KEY}.
- REST data plane — X-API-Key: <your-assigned-api-key> (Authorization: Bearer <token> is also accepted by the server). POST /v1/agents/register is the unauthenticated self-registration exception when its onboarding conditions allow it.
- Identity headers are attribution only and never grant access.

## Base URL

Set BASE_URL to the deployment origin. The hosted product uses https://xmemo.dev; the committed OpenAPI document also declares http://localhost:8000 for local development and https://api.memory-os.example.com as an example server. REST data-plane calls use /v1 paths.

```bash
BASE_URL="${BASE_URL:-https://xmemo.dev}"
curl -sS "$BASE_URL/v1/recall?query=connection%20check&limit=1" \
  -H "X-API-Key: $XMEMO_KEY"
```

## REST authentication header

Most REST requests carry the API key header. Requests without a valid credential are rejected before any memory is read or written; POST /v1/agents/register is the documented self-registration exception.

```http
X-API-Key: <your-assigned-api-key>
```

## MCP authentication

OAuth clients only need the hosted server URL — the grant supplies memory:read and memory:write. Direct and headless clients read the token from the environment instead.

```json
{
  "servers": {
    "XMemo": {
      "type": "http",
      "url": "https://xmemo.dev/mcp"
    }
  }
}
```

## Scopes

The server evaluates the credential's scopes and the requested memory space independently. Use memory:read for recall, search, context, list, and project reads; use memory:write for writes and mutations. Knowledge operations strictly require knowledge:read and reject memory:read tokens with 403. Advanced direct tokens may use narrower capabilities such as memory:update, memory:delete, memory:restore, memory:redact, or memory:hard_delete. Legacy REST aliases read:memories and write:memories remain compatibility values; scope never widens owner, team, or token-space authorization.

- Read: memory:read.
- Write: memory:write; mutation operations may require a narrower capability when the token profile supports it.
- Knowledge: knowledge:read; strictly required for knowledge search and listing (memory:read tokens return 403).
- Project/team access: the token's owner or bound team and live role must also authorize the requested scope/team_id.
- Attribution headers and source fields identify a caller; they are not scopes and do not grant access.

## Error schema

The OpenAPI paths declare HTTPValidationError for request validation (422) and otherwise leave most response schemas untyped. The default REST error remains a JSON object with a detail value. Recognized authorization failures may also be requested as RFC 9457-style application/problem+json; use the code field for machine handling rather than matching prose.

```json
{
  "detail": "invalid_token"
}

{
  "type": "urn:xmemo:problem:invalid_token",
  "title": "Invalid access token",
  "status": 401,
  "code": "invalid_token",
  "detail": "The presented access token is missing, expired, revoked, or otherwise invalid."
}
```

## Rate limits

OpenAPI does not publish rate-limit quotas. The runtime uses a 60-second fixed window when enabled (enabled by default outside development/local/test): the data-plane category is 600 requests per minute, memory writes use a 180-per-minute endpoint policy, and memory search/recall/context reads use a 300-per-minute endpoint policy. Operators can override these values with the MEMORY_OS_RATE_LIMIT_* environment variables; do not hard-code a quota in a client.

- 429 response: { detail: Rate limit exceeded, category, policy, limit, window_seconds, retry_after_seconds }.
- 429 headers: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and X-RateLimit-Policy.
- Successful responses also expose the X-RateLimit-* limit, remaining, reset, and policy headers when the limiter is enabled.

