Skip to main content

Overview

Local token authentication uses a single shared bearer token for all API requests. This mode is designed for:
  • Self-hosted deployments with trusted network access
  • Development and testing environments
  • Single-user or single-team deployments
Local mode maps all authenticated requests to a single user account ([email protected]). Do not use this mode for multi-user production deployments.

Configuration

Backend Configuration

Set the following environment variables in your backend .env file:
backend/.env
AUTH_MODE=local
LOCAL_AUTH_TOKEN=your-secure-token-here-must-be-at-least-50-characters-long
AUTH_MODE
string
required
Must be set to local to enable local token authentication
LOCAL_AUTH_TOKEN
string
required
The shared bearer token used for all API requests. Must be at least 50 characters long.Generate a secure token with:
openssl rand -base64 48

Frontend Configuration

Set the following environment variables in your frontend .env.local file:
frontend/.env.local
NEXT_PUBLIC_AUTH_MODE=local
NEXT_PUBLIC_LOCAL_AUTH_TOKEN=same-token-as-backend
NEXT_PUBLIC_AUTH_MODE
string
required
Must be set to local to enable local token mode in the frontend
NEXT_PUBLIC_LOCAL_AUTH_TOKEN
string
required
Must match the backend LOCAL_AUTH_TOKEN exactly. The frontend uses this to authenticate automatically without a login screen.
The frontend will also check sessionStorage["mc_local_auth_token"] if the environment variable is not set.

Authentication Flow

1

Token Configuration

Configure LOCAL_AUTH_TOKEN in backend and frontend environment variables
2

Frontend Auto-Authentication

Frontend automatically includes the token in all API requests via the Authorization header
3

Backend Token Validation

Backend extracts token from Authorization: Bearer <token> header and performs constant-time comparison against LOCAL_AUTH_TOKEN
4

User Context Resolution

On successful authentication, backend returns or creates the local admin user with:

API Usage

Making Authenticated Requests

Include the token in the Authorization header:
curl -X GET https://api.example.com/api/v1/users/me \
  -H "Authorization: Bearer your-local-auth-token-here"

Bootstrap User Context

curl -X POST https://api.example.com/api/v1/auth/bootstrap \
  -H "Authorization: Bearer your-local-auth-token-here"
Response:
{
  "id": "11111111-1111-1111-1111-111111111111",
  "clerk_user_id": "local-auth-user",
  "email": "[email protected]",
  "name": "Local User",
  "preferred_name": null,
  "pronouns": null,
  "timezone": "America/Los_Angeles",
  "notes": null,
  "context": null,
  "is_super_admin": false
}

Token Validation Details

Backend Implementation

The backend validates tokens in app/core/auth.py:_resolve_local_auth_context():
  1. Extract token from Authorization: Bearer <token> header
  2. Validate format: Token must be present and non-empty
  3. Compare tokens: Uses hmac.compare_digest() for constant-time comparison to prevent timing attacks
  4. Return user: On success, returns or creates the local admin user
from hmac import compare_digest

expected = settings.local_auth_token.strip()
if not expected or not compare_digest(token, expected):
    raise HTTPException(status_code=401)

Security Properties

Constant-time comparison prevents timing attacks that could leak token information
Token length requirement (50+ characters) ensures sufficient entropy
Single user model: All authenticated requests map to the same user account

Error Handling

Missing Token

Request:
curl -X GET https://api.example.com/api/v1/users/me
Response: 401 Unauthorized
{
  "detail": "Not authenticated"
}

Invalid Token

Request:
curl -X GET https://api.example.com/api/v1/users/me \
  -H "Authorization: Bearer wrong-token"
Response: 401 Unauthorized
{
  "detail": "Not authenticated"
}

Malformed Authorization Header

Request:
curl -X GET https://api.example.com/api/v1/users/me \
  -H "Authorization: your-token"
Response: 401 Unauthorized (missing “Bearer” prefix)

Common Issues

Token Too Short

Error: LOCAL_AUTH_TOKEN must be at least 50 charactersSolution: Generate a longer token:
openssl rand -base64 48

Frontend/Backend Token Mismatch

Symptom: Frontend shows “Not authenticated” errorsSolution: Ensure NEXT_PUBLIC_LOCAL_AUTH_TOKEN in frontend matches LOCAL_AUTH_TOKEN in backend exactly

CORS Errors

Symptom: Browser blocks API requests with CORS errorsSolution: Add your frontend origin to CORS_ORIGINS in backend .env:
CORS_ORIGINS=http://localhost:3000,http://192.168.1.100:3000

Migrating to Clerk

To migrate from local token to Clerk authentication:
1

Set up Clerk account

Create a Clerk account at clerk.com
2

Update backend configuration

backend/.env
AUTH_MODE=clerk
CLERK_SECRET_KEY=sk_live_...
CLERK_API_URL=https://api.clerk.com
3

Update frontend configuration

frontend/.env.local
NEXT_PUBLIC_AUTH_MODE=clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
4

Restart services

Restart backend and frontend services to apply changes
See Clerk Authentication for detailed setup instructions.

Best Practices

Generate strong tokens: Use cryptographically secure random token generators
Rotate tokens regularly: Update LOCAL_AUTH_TOKEN periodically in secure deployments
Restrict network access: Use firewall rules or VPN to limit API access
Use HTTPS: Always use HTTPS in production to prevent token interception
Never commit tokens: Add .env and .env.local to .gitignore

Next Steps

Clerk Authentication

Upgrade to multi-user JWT authentication

Agent Tokens

Learn about agent authentication

Build docs developers (and LLMs) love