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

# Authentication

> How Memanto authenticates Moorcheh and authorizes memory operations through session tokens.

# Authentication

Memanto uses a **server-side Moorcheh API key** combined with **per-agent session tokens** to scope memory operations, plus a separate **management credential** that gates agent lifecycle endpoints (create/list/get/delete/activate/deactivate an agent, and the status endpoint).

<CardGroup cols={2}>
  <Card title="Server (Moorcheh)" icon="key">
    Memanto reads `MOORCHEH_API_KEY` from its environment / configuration and authenticates **on the server** when calling Moorcheh.

    ```bash theme={null}
    export MOORCHEH_API_KEY=your_moorcheh_key
    ```
  </Card>

  <Card title="Memory Operations (Client)" icon="database">
    Memory endpoints require a **session token** in the `X-Session-Token` header. Tokens are obtained by activating an agent.

    ```http theme={null}
    X-Session-Token: your_jwt_token
    ```
  </Card>
</CardGroup>

## Server-Side Moorcheh API Key

Memanto does not accept a Moorcheh API key from clients. The key is set once on the server and is used for every Moorcheh call Memanto makes:

```bash theme={null}
# Required on the Memanto server
export MOORCHEH_API_KEY=your_moorcheh_key
```

If the key is missing or invalid, Memanto fails fast at startup with `MOORCHEH_API_KEY is not configured` or `MOORCHEH_API_KEY is invalid`.

### Getting a Moorcheh API Key

1. Go to [https://console.moorcheh.ai/api-keys](https://console.moorcheh.ai/api-keys)
2. Create a new API key
3. Configure it on the Memanto server (env var, secrets manager, etc.)

## Session Token Authentication

### When Session Tokens Are Required

Memory operations require an `X-Session-Token` header obtained from agent activation:

* `POST /api/v2/agents/{agent_id}/remember`
* `POST /api/v2/agents/{agent_id}/batch-remember`
* `PATCH /api/v2/agents/{agent_id}/memories/{memory_id}`
* `POST /api/v2/agents/{agent_id}/remember/extract`
* `POST /api/v2/agents/{agent_id}/upload-file`
* `DELETE /api/v2/agents/{agent_id}/memories/{memory_id}`
* `POST /api/v2/agents/{agent_id}/recall`
* `POST /api/v2/agents/{agent_id}/recall/as-of`
* `POST /api/v2/agents/{agent_id}/recall/changed-since`
* `POST /api/v2/agents/{agent_id}/recall/recent`
* `POST /api/v2/agents/{agent_id}/answer`
* `POST /api/v2/agents/{agent_id}/daily-summary`
* `POST /api/v2/agents/{agent_id}/conflicts/generate`
* `GET  /api/v2/agents/{agent_id}/conflicts`
* `POST /api/v2/agents/{agent_id}/conflicts/resolve`
* `POST /api/v2/agents/{agent_id}/deactivate`

The session must match `agent_id` in the path; otherwise the request is rejected.

### Cookie-Based Authentication (Browser / Web UI Clients)

As an alternative to the `X-Session-Token` header, [Activate Agent](/api-reference/sessions/activate-agent) also sets an `HttpOnly`, `SameSite=Strict` cookie named `memanto_session_token`. `get_current_session` accepts **either** the header **or** the cookie — browser clients (like the built-in Web UI) never need to read the token out of JavaScript.

* The cookie is set on `POST /api/v2/agents/{agent_id}/activate` and cleared on `POST /api/v2/agents/{agent_id}/deactivate`.
* The cookie's `Secure` attribute is set **dynamically** from the actual request scheme (`Secure` when the request arrived over HTTPS, omitted over plain HTTP). Memanto binds `0.0.0.0` with no built-in TLS by default, so a hardcoded `Secure` flag would silently stop browsers from ever sending the cookie back in that default deployment — put Memanto behind an HTTPS-terminating proxy in production to get `Secure` cookies.
* If a near-expiry session is auto-renewed mid-request, the server transparently re-sets the cookie with the new token so cookie-authenticated clients don't go stale.
* API clients that use the `X-Session-Token` header (CLI, SDKs, direct API integrations) are unaffected — the cookie is purely additive for browser-based callers.

### Management Endpoint Authentication (Agent Lifecycle)

Agent-lifecycle endpoints don't take a session token (there's no session yet), but as of `v0.2.7` they **do** require authorization — either a management credential or a loopback client:

* `POST /api/v2/agents` — Create agent
* `GET  /api/v2/agents` — List agents
* `GET  /api/v2/agents/{agent_id}` — Get agent details
* `DELETE /api/v2/agents/{agent_id}` — Delete agent
* `POST /api/v2/agents/{agent_id}/activate` — Activate (returns the token)
* `POST /api/v2/agents/{agent_id}/deactivate` — Deactivate (also checked here, in addition to the session token above)
* `GET  /api/v2/status` — Inspect the active session

<Warning>
  Prior to `v0.2.7`, these endpoints only checked that the **server** had a configured `MOORCHEH_API_KEY` — not that the **caller** was authorized. Combined with the default `HOST=0.0.0.0` bind, any network peer could create agents, activate sessions, and obtain session tokens. Upgrade if you're running an older version and Memanto is reachable from outside `localhost`.
</Warning>

Access is granted when **either** of these is true:

1. **The caller presents the management credential**, matched with a constant-time comparison against the configured server credential:
   ```http theme={null}
   Authorization: Bearer <key>
   ```
   or
   ```http theme={null}
   X-Api-Key: <key>
   ```
   The expected credential is `MOORCHEH_API_KEY` on the **cloud** backend, or `MEMANTO_SECRET_KEY` on the **on-prem** backend (see [Session cookie hardening](#cookie-based-authentication-browser-web-ui-clients) for how that same secret is generated when unset).
2. **The request originates from the loopback interface** (`127.0.0.1` / `::1`, including IPv4-mapped IPv6) — so the local desktop CLI and Web UI keep working without attaching a key on every call.

Requests that satisfy neither condition get:

```json 401 - Unauthorized (Management Auth Required) theme={null}
{
  "detail": "Unauthorized. Agent management endpoints require either a loopback client or a valid management credential (Authorization: Bearer <key> or X-Api-Key)."
}
```

**Endpoints that remain fully open** (no management credential, no loopback requirement):

* `GET  /health`, `GET  /ready`, `GET  /live` — [Health & Readiness](/api-reference/system/health) probes

### Getting a Session Token

1. Activate an agent (from `localhost`, no management credential needed):

```bash theme={null}
curl -X POST "http://localhost:8000/api/v2/agents/my-agent/activate"
```

From a non-loopback host, attach the management credential:

```bash theme={null}
curl -X POST "https://memanto.example.com/api/v2/agents/my-agent/activate" \
  -H "Authorization: Bearer $MOORCHEH_API_KEY"
```

2. Response contains a session token:

```json theme={null}
{
  "session_id": "9f733fdb-ebf2-494e-8eb6-fb3320d6020d",
  "session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "agent_id": "my-agent",
  "namespace": "memanto_agent_my-agent",
  "started_at": "2026-05-09T02:40:00Z",
  "expires_at": "2026-05-09T08:40:00Z",
  "pattern": "support",
  "status": "active"
}
```

3. Use the token in subsequent requests:

```http theme={null}
X-Session-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

### Example Request with Session Token

```bash theme={null}
curl -X POST "http://localhost:8000/api/v2/agents/my-agent/remember" \
  -H "X-Session-Token: eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{"content": "Hello", "type": "fact"}'
```

### In Python

```python theme={null}
import httpx

base_url = "http://localhost:8000"

# 1. Activate to get a session token
activate_resp = httpx.post(f"{base_url}/api/v2/agents/my-agent/activate")
session_token = activate_resp.json()["session_token"]

# 2. Use the session token for memory operations
headers = {
    "X-Session-Token": session_token,
    "Content-Type": "application/json",
}

remember_resp = httpx.post(
    f"{base_url}/api/v2/agents/my-agent/remember",
    headers=headers,
    json={"content": "Hello", "type": "fact"},
)
```

## Session Token Details

### Token Format

Session tokens are JWT (JSON Web Tokens):

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJhZ2VudF9pZCI6Im15LWFnZW50IiwiZXhwaXJlc19hdCI6IjIwMjYtMDUtMDlUMDg6NDA6MDBaIn0.
[signature]
```

### Token Expiration

* **Duration**: configured by the server via `SESSION_DEFAULT_DURATION_HOURS` (typically 6 hours).
* **Auto-renewal**: Memanto auto-renews sessions that are near expiry on the next memory request.
* **Renewal**: activate a new session with `POST /api/v2/agents/{agent_id}/activate`.

### Decode Token (Python)

```python theme={null}
import jwt

token = "eyJhbGc..."
payload = jwt.decode(token, options={"verify_signature": False})

print(f"Agent: {payload['agent_id']}")
print(f"Expires: {payload['expires_at']}")
```

## Common Errors

### Missing Session Token

```json theme={null}
{
  "detail": "Missing session token. Use X-Session-Token header."
}
```

**Fix:** Activate the agent and include the returned token in `X-Session-Token`.

### Invalid Session Token

```json theme={null}
{
  "detail": {
    "error": "InvalidSessionToken",
    "message": "Invalid session token: Not enough segments",
    "details": {}
  }
}
```

**Fix:** Re-activate the agent and use the freshly returned token.

### Session Expired

```json theme={null}
{
  "detail": {
    "error": "SessionExpired",
    "message": "Session has expired",
    "details": {}
  }
}
```

**Fix:** Activate a new session with `POST /api/v2/agents/{agent_id}/activate`.

### Management Auth Required

```json theme={null}
{
  "detail": "Unauthorized. Agent management endpoints require either a loopback client or a valid management credential (Authorization: Bearer <key> or X-Api-Key)."
}
```

**Fix:** Attach `Authorization: Bearer <key>` or `X-Api-Key: <key>` (the cloud `MOORCHEH_API_KEY` or the on-prem `MEMANTO_SECRET_KEY`), or call from a loopback client. See [Management Endpoint Authentication](#management-endpoint-authentication-agent-lifecycle).

### Session / Agent Mismatch

If the session token was issued for a different agent than the one in the URL path, the server returns `500` with:

```json theme={null}
{
  "detail": {
    "error": "InternalServerError",
    "message": "An unexpected error occurred",
    "details": {
      "original_error": "Session is for agent 'other-agent', cannot access 'my-agent'"
    }
  }
}
```

**Fix:** Activate the correct agent or call the endpoint with the matching `agent_id`.

## Best Practices

### <Icon icon="check" /> DO

* Store `MOORCHEH_API_KEY` as a server-side secret (env var, Secrets Manager, etc.)
* Keep session tokens in memory on the client (don't persist long-term)
* Rotate the Moorcheh key periodically
* Treat session tokens as sensitive — they grant memory access for an agent
* If Memanto is reachable from outside `localhost`, attach `Authorization: Bearer <key>` or `X-Api-Key` on agent-lifecycle calls — don't rely on network placement alone

### <Icon icon="xmark" /> DON'T

* Commit `MOORCHEH_API_KEY` to source control
* Reuse a session token across different agents
* Log session tokens (or the management credential) to files or telemetry
* Bind Memanto to `0.0.0.0` on an untrusted network without also setting a real `MOORCHEH_API_KEY` / `MEMANTO_SECRET_KEY` — that credential is what gates agent-lifecycle access for non-loopback callers

## Security

### API Key Management

**Development:**

```bash theme={null}
export MOORCHEH_API_KEY=dev_key
```

**Production (AWS Secrets Manager):**

```python theme={null}
import boto3

client = boto3.client("secretsmanager")
secret = client.get_secret_value(SecretId="moorcheh/api-key")
api_key = secret["SecretString"]
```

**Production (Environment):**

```bash theme={null}
# In your deployment platform
MOORCHEH_API_KEY=prod_key
```

### Session Token Security

* Tokens are JWT — treat as sensitive
* Don't log tokens
* Don't expose in client-side code that ships to end users
* Short-lived (configurable, default \~6 hours)
* Unique per activation

## Next Steps

* [Activate Agent](/api-reference/sessions/activate-agent) to obtain a session token
* [Get Current Session](/api-reference/sessions/get-current-session) to inspect the active session
* [Remember](/api-reference/data/remember) to start storing memories
