Skip to content

Authentication

AutoMem uses a two-tier token-based authentication system to control access to different classes of operations. All endpoints except /health, /backup, and /viewer* (plus OPTIONS preflight requests) require a valid API token when AUTOMEM_API_TOKEN is configured. The /backup endpoint bypasses the API token guard and is protected by the admin token only.

For deployment-specific token generation on Railway, see Railway Deployment. For complete endpoint documentation with authentication requirements, see Memory Operations.


Token TypeEnvironment VariableRequired ForPurpose
API TokenAUTOMEM_API_TOKENAll endpoints except /health, /backup, and /viewer* (and OPTIONS preflights)Standard memory operations (store, recall, update, delete)
Admin TokenADMIN_API_TOKEN/admin/reembed, /admin/sync, /enrichment/reprocess, /entities/audit, /entity/<slug>/merge, and /backupPrivileged operations (reprocessing, re-embedding, bulk operations)

AutoMem accepts authentication credentials via three methods, checked in the following priority order:

graph TD
    Request["Incoming Request"]

    CheckBearer{"Authorization header<br/>starts with 'Bearer'?"}
    ExtractBearer["Extract token<br/>from Bearer string"]

    CheckCustomHeader{"X-API-Key header?"}
    ExtractHeader["Extract token<br/>from header"]

    CheckQuery{"Query param<br/>api_key?"}
    ExtractQuery["Extract token<br/>from query string"]

    NoToken["Return None<br/>→ 401 Unauthorized"]
    ValidateToken["Validate against<br/>AUTOMEM_API_TOKEN"]

    Request --> CheckBearer
    CheckBearer -->|Yes| ExtractBearer
    CheckBearer -->|No| CheckCustomHeader

    CheckCustomHeader -->|Yes| ExtractHeader
    CheckCustomHeader -->|No| CheckQuery

    CheckQuery -->|Yes| ExtractQuery
    CheckQuery -->|No| NoToken

    ExtractBearer --> ValidateToken
    ExtractHeader --> ValidateToken
    ExtractQuery --> ValidateToken

Standard OAuth 2.0-style authentication using the Authorization header:

Terminal window
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
https://your-service.railway.app/recall?q=query

Advantages:

  • Industry standard
  • Automatically handled by most HTTP libraries
  • Cannot be logged in server access logs (more secure than query params)

Alternative header-based authentication using X-API-Key (only X-API-Key is checked — not X-API-Token):

Terminal window
curl -H "X-API-Key: YOUR_API_TOKEN" \
https://your-service.railway.app/recall?q=query

Use this when client libraries do not support Bearer tokens easily.

Fallback authentication via URL query string using only api_key (not apiKey or api_token):

Terminal window
curl "https://your-service.railway.app/recall?q=query&api_key=YOUR_API_TOKEN"

This diagram shows how requests flow through the Flask API authentication layer:

graph LR
    subgraph "Token Sources"
        BearerHeader["Authorization: Bearer TOKEN"]
        APIKeyHeader["X-API-Key: TOKEN"]
        QueryParam["?api_key=TOKEN"]
    end

    subgraph "Flask API :8001"
        RequireAPIToken["require_api_token()"]
        ExtractToken["extract_api_token(request_obj,<br/>configured_api_token)<br/>→ token string or None"]
        ValidateToken["Compare extracted token<br/>vs AUTOMEM_API_TOKEN"]
        CheckLevel["Check endpoint<br/>requires ADMIN?"]
        ValidateAdmin["Validate<br/>ADMIN_API_TOKEN"]
        ProcessRequest["Route to handler"]
    end

    BearerHeader --> RequireAPIToken
    APIKeyHeader --> RequireAPIToken
    QueryParam --> RequireAPIToken

    RequireAPIToken -->|"OPTIONS, /viewer*, /health,<br/>or AUTOMEM_API_TOKEN unset"| ProcessRequest
    RequireAPIToken -->|"/backup skips the API token"| ValidateAdmin
    RequireAPIToken --> ExtractToken
    ExtractToken --> ValidateToken
    ValidateToken -->|Valid| CheckLevel
    ValidateToken -->|Token missing/invalid| Reject401["401 Unauthorized"]

    CheckLevel -->|Standard| ProcessRequest
    CheckLevel -->|Admin endpoint| ValidateAdmin
    ValidateAdmin -->|Valid| ProcessRequest
    ValidateAdmin -->|"Admin token missing or incorrect"| Reject401Admin["401 Unauthorized"]
    ValidateAdmin -->|"ADMIN_API_TOKEN not configured"| Reject403["403 Forbidden"]

Most admin endpoints require both the API token and an additional admin token. AutoMem reads the admin token from the X-Admin-Token header, then the X-Admin-Api-Key header, then the admin_token query parameter, and compares the first non-empty value it finds against ADMIN_API_TOKEN. Prefer X-Admin-Token:

Terminal window
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Admin-Token: YOUR_ADMIN_TOKEN" \
-X POST https://your-service.railway.app/enrichment/reprocess
EndpointMethodPurposeAPI TokenAdmin Token
/admin/reembedPOSTRegenerate embeddings in batchesYesYes
/admin/syncPOSTNon-destructive drift repairYesYes
/enrichment/reprocessPOSTRe-queue memories for enrichmentYesYes
/entities/auditGETDry-run entity cleanup auditYesYes
/entity/<slug>/mergePOSTMerge one entity into anotherYesYes
/backupGETExport restore-compatible backup archiveNoYes

Note: /enrichment/status requires an API token when AUTOMEM_API_TOKEN is configured. The API token guard skips only /health, /backup, /viewer*, and OPTIONS requests. The /backup endpoint is still protected by the admin token. /viewer* is a compatibility route that redirects to the standalone graph viewer at GRAPH_VIEWER_URL. It is registered only while ENABLE_GRAPH_VIEWER is enabled (the default) and is not a data-API exemption, so the viewer’s own API calls still need the API token.


graph TB
    subgraph "Public Endpoints"
        Health["/health<br/>GET"]
        Viewer["/viewer*<br/>GET"]
    end

    subgraph "API Token Required"
        Memory["/memory<br/>POST, GET, PATCH, DELETE"]
        Recall["/recall<br/>GET"]
        Associate["/associate<br/>POST"]
        ByTag["/memory/by-tag<br/>GET"]
        Consolidate["/consolidate<br/>POST"]
        ConsolidateStatus["/consolidate/status<br/>GET"]
        Analyze["/analyze<br/>GET"]
        StartupRecall["/startup-recall<br/>GET"]
        EnrichStatus["/enrichment/status<br/>GET"]
    end

    subgraph "API Token + Admin Token Required"
        Reembed["/admin/reembed<br/>POST"]
        Sync["/admin/sync<br/>POST"]
        Reprocess["/enrichment/reprocess<br/>POST"]
        EntitiesAudit["/entities/audit<br/>GET"]
        EntityMerge["/entity/&lt;slug&gt;/merge<br/>POST"]
    end

    subgraph "Admin Token Only (no API token)"
        Backup["/backup<br/>GET"]
    end

    style Health fill:#90EE90
    style Viewer fill:#90EE90
    style Memory fill:#FFD700
    style Recall fill:#FFD700
    style Associate fill:#FFD700
    style ByTag fill:#FFD700
    style Consolidate fill:#FFD700
    style ConsolidateStatus fill:#FFD700
    style Analyze fill:#FFD700
    style StartupRecall fill:#FFD700
    style EnrichStatus fill:#FFD700
    style Reembed fill:#FF6B6B
    style Sync fill:#FF6B6B
    style Reprocess fill:#FF6B6B
    style EntitiesAudit fill:#FF6B6B
    style EntityMerge fill:#FF6B6B
    style Backup fill:#FF6B6B
CategoryEndpointsAPI TokenAdmin Token
Public/health, /viewer*NoNo
Standard/memory, /recall, /associate, /memory/by-tag, /consolidate, /consolidate/status, /analyze, /startup-recall, /enrichment/statusYesNo
Admin/admin/reembed, /admin/sync, /enrichment/reprocess, /entities/audit, /entity/<slug>/mergeYesYes
Admin-only/backupNoYes

Configure authentication tokens via environment variables loaded in this order:

  1. Process environment (e.g., export AUTOMEM_API_TOKEN=...)
  2. .env file in project root
  3. ~/.config/automem/.env (user-specific configuration)

Railway (Automatic):

For Railway deployments, set AUTOMEM_API_TOKEN and ADMIN_API_TOKEN as Railway environment variables or generated secrets in the service configuration. The repo no longer ships a standalone railway-template.json for this.

Manual (Local Development):

Generate secure tokens using OpenSSL:

Terminal window
# Generate API token
openssl rand -hex 32
# Generate Admin token (use a different value)
openssl rand -hex 32

import requests
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
response = requests.post(
"https://your-service.railway.app/memory",
headers=headers,
json={"content": "Important decision made today", "type": "Decision"}
)
const response = await fetch("https://your-service.railway.app/recall?q=decisions", {
headers: {
"Authorization": `Bearer ${apiToken}`,
}
});
const data = await response.json();
Terminal window
# Store a memory
curl -X POST https://your-service.railway.app/memory \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": "Prefer PostgreSQL for relational data", "type": "Preference"}'
# Recall memories
curl "https://your-service.railway.app/recall?q=database+preferences" \
-H "Authorization: Bearer YOUR_TOKEN"

NPM Package (@verygoodplugins/mcp-automem)

Section titled “NPM Package (@verygoodplugins/mcp-automem)”

Desktop tools like Claude Desktop and Cursor IDE use the NPM package, which requires API token configuration in the platform’s MCP config file:

{
"mcpServers": {
"automem": {
"command": "npx",
"args": ["-y", "@verygoodplugins/mcp-automem"],
"env": {
"AUTOMEM_API_URL": "https://your-service.railway.app",
"AUTOMEM_API_KEY": "YOUR_API_TOKEN"
}
}
}
}

The client automatically injects the token as Authorization: Bearer header on all requests.

For cloud-based AI platforms (ChatGPT, ElevenLabs), the SSE bridge requires AUTOMEM_API_TOKEN set in the Railway environment. The bridge validates incoming requests against this token and forwards them to the AutoMem API transparently.


PracticeDescriptionPriority
Strong tokensUse cryptographically random tokens (32+ bytes)Critical
Environment variablesNever hardcode tokens in code or commit to GitCritical
Separate admin tokensUse different tokens for API and admin accessCritical
HTTPS onlyAlways use HTTPS in production (Railway provides automatically)Critical
Prefer Bearer authUse Authorization: Bearer over query paramsHigh
Rotate regularlyChange tokens every 90 days or after suspected exposureHigh
Environment separationDifferent tokens for dev/staging/productionHigh
Monitor logsWatch for 401 errors indicating unauthorized attemptsMedium
Audit trailLog who performs admin operations (via admin token)Medium
MistakeRiskSolution
Committing tokens to GitPublic exposure, unauthorized accessUse .gitignore, environment variables
Using same token everywhereSingle point of compromiseSeparate tokens per environment
Query param authentication in productionTokens logged in server logsUse Bearer header
No admin token separationAnyone with API access can perform admin opsConfigure separate ADMIN_API_TOKEN
Weak tokens (e.g., “password123”)Easy to guess/brute forceUse cryptographic generators

When rotating tokens (for example, after suspected exposure or periodic maintenance):

  1. Generate new tokens: openssl rand -hex 32
  2. Update server environment variables (Railway dashboard or CLI)
  3. Update all clients with new tokens before removing old tokens
  4. Test connectivity with new tokens
  5. Remove old tokens from server configuration entirely
  6. Restart the service to ensure old tokens are not cached

Symptom: All requests return 401 Unauthorized

Common causes:

  1. Token not set in environment variable — verify with echo $AUTOMEM_API_TOKEN
  2. Typo in token value — check for trailing spaces or newlines
  3. Using wrong token (API token vs admin token)
  4. Token mismatch between client and server

Diagnosis:

Terminal window
# Test your token directly
curl -v -H "Authorization: Bearer YOUR_TOKEN" \
https://your-service.railway.app/recall?q=test

Symptom: Standard endpoints work, but admin endpoints return 401 Unauthorized

Common causes:

  1. Missing admin token. AutoMem reads it from the X-Admin-Token header, the X-Admin-Api-Key header, or the admin_token query parameter. Admin endpoints other than /backup also need the API token
  2. Admin token mismatch between client and server

Symptom: Admin endpoints return 403 Forbidden with “Admin token not configured”

Cause: ADMIN_API_TOKEN is not set on the server. The server rejects admin requests with 403 before it compares any supplied token, so a missing or wrong token on a configured server returns 401 instead. Set ADMIN_API_TOKEN and restart the service.

If a token is exposed (committed to Git, shared in logs):

  1. Immediate rotation: Generate a new token and update server configuration — deploy immediately
  2. Audit access: Check server logs for unauthorized requests; look for unusual patterns in /health or /analyze endpoints
  3. Revoke old token: Remove from environment variables and restart the service to ensure it is not cached