knowledge-base/AUTH_SETUP.md
2025-10-23 22:22:07 +05:30

7.4 KiB

Authentication Setup - Mem0 Memory Server

Implementation Complete

A simple but effective API key-based authentication layer has been added to ensure users can only access their own memories.

🔐 How It Works

1. API Key to User Mapping

API keys are mapped to user IDs in the .env file:

API_KEYS='{"sk-alice-test-key-12345": "alice", "sk-bob-test-key-67890": "bob", "sk-carol-test-key-abcdef": "carol"}'

2. Authentication Flow

  1. Client sends request with X-API-Key header
  2. Backend validates API key against configured mapping
  3. Backend extracts authenticated user_id
  4. Backend verifies user can only access their own data
  5. Request proceeds or 401/403 error returned

3. Protected Endpoints

All memory-related endpoints now require authentication:

Endpoint Method Auth Required User Isolation
/chat POST User can only chat as themselves
/memories POST User can only add to own memories
/memories/search POST User can only search own memories
/memories/{user_id} GET User can only view own memories
/memories PUT User can only update own memories
/memories/{memory_id} DELETE User can only delete own memories
/memories/user/{user_id} DELETE User can only delete own memories
/graph/relationships/{user_id} GET User can only view own relationships
/stats/{user_id} GET User can only view own stats
/health GET N/A (Public)
/stats GET N/A (Global stats)
/models GET N/A (Public)

📝 Configuration

Environment Setup

1. Update .env file:

# Add API key mapping
API_KEYS='{"api_key_1": "user1", "api_key_2": "user2"}'

2. Generate Secure API Keys (Production):

# Generate a random 32-character API key
openssl rand -hex 32

# Example output: sk-a1b2c3d4e5f6...

3. Restart Services:

docker-compose down
docker-compose up -d

🧪 Testing Authentication

Test 1: No API Key (Should Fail - 403)

curl -X POST "http://localhost:8000/memories" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Test"}],"user_id":"alice"}'

# Response: {"detail":"Not authenticated"}

Test 2: Invalid API Key (Should Fail - 401)

curl -X POST "http://localhost:8000/memories" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: invalid-key" \
  -d '{"messages":[{"role":"user","content":"Test"}],"user_id":"alice"}'

# Response: {"detail":"Invalid API key"}

Test 3: Valid API Key (Should Succeed - 200)

curl -X POST "http://localhost:8000/memories" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sk-alice-test-key-12345" \
  -d '{"messages":[{"role":"user","content":"My name is Alice"}],"user_id":"alice"}'

# Response: {"added_memories":[...], "message":"Memories added successfully"}

Test 4: Cross-User Access (Should Fail - 403)

# Alice trying to access Bob's data
curl -X POST "http://localhost:8000/memories" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sk-alice-test-key-12345" \
  -d '{"messages":[{"role":"user","content":"Test"}],"user_id":"bob"}'

# Response: {"detail":"Access denied: You can only add memories for yourself (authenticated as 'alice')"}

Test 5: Authenticated Chat

curl -X POST "http://localhost:8000/chat" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sk-alice-test-key-12345" \
  -d '{"message":"What do you know about me?","user_id":"alice"}'

# Response: {"response":"Based on your memories...", "memories_used":5, ...}
curl -X POST "http://localhost:8000/memories/search" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sk-bob-test-key-67890" \
  -d '{"query":"tennis","user_id":"bob"}'

# Response: {"memories":[...], "total_count":4}

🔧 Implementation Details

Files Modified/Created:

  1. backend/auth.py (NEW)

    • AuthService class for API key validation
    • get_current_user() FastAPI dependency
    • verify_user_access() for cross-user protection
  2. backend/config.py (UPDATED)

    • Added api_keys field using proper Pydantic V2 syntax
    • Added api_key_mapping property to parse JSON
    • Uses validation_alias with AliasChoices for env var mapping
  3. backend/main.py (UPDATED)

    • All protected endpoints now use authenticated_user = Depends(get_current_user)
    • Added user isolation checks in each endpoint
  4. docker-compose.yml (UPDATED)

    • Added API_KEYS environment variable mapping
  5. .env (UPDATED)

    • Added API_KEYS configuration
  6. .env.example (UPDATED)

    • Added API_KEYS template with security notes

🎯 Security Features Implemented

API Key Authentication: Every protected request requires valid API key User Isolation: Users can only access their own data Cross-User Protection: Prevents user A from accessing user B's memories Structured Logging: All auth events logged with correlation IDs Environment-Based Config: API keys stored in .env (not hardcoded) Clear Error Messages: Informative 401/403 responses

🔒 Production Recommendations

Current Setup ( Completed)

  • API key authentication
  • User isolation
  • Environment-based configuration
  • Cross-user access protection

Future Enhancements (Optional)

  • Move API keys to secrets manager (AWS Secrets Manager, HashiCorp Vault)
  • Add API key rotation mechanism
  • Add rate limiting per API key
  • Add API key expiration
  • Add audit logging for security events
  • Add API key scopes/permissions
  • Add HTTPS enforcement
  • Add request signing for extra security

📊 Test Results

All authentication tests PASSED

Test Result HTTP Status
No API key Blocked 403
Invalid API key Blocked 401
Valid API key Allowed 200
Cross-user access Blocked 403
Authenticated chat Works 200
Authenticated search Works 200
Stats isolation Blocked 403

💡 Usage Example

import requests

# Configure API key
API_KEY = "sk-alice-test-key-12345"
BASE_URL = "http://localhost:8000"

headers = {
    "Content-Type": "application/json",
    "X-API-Key": API_KEY
}

# Add memory
response = requests.post(
    f"{BASE_URL}/memories",
    headers=headers,
    json={
        "messages": [{"role": "user", "content": "I love Python programming"}],
        "user_id": "alice"
    }
)

print(response.json())
# {"added_memories": [...], "message": "Memories added successfully"}

# Chat with memory
response = requests.post(
    f"{BASE_URL}/chat",
    headers=headers,
    json={
        "message": "What do I love?",
        "user_id": "alice"
    }
)

print(response.json()["response"])
# "Based on your memories, you love Python programming"

🚀 Ready for Production

The authentication layer is now production-ready for basic deployment with:

  • Simple API key authentication
  • User data isolation
  • Proper error handling
  • Environment-based configuration
  • Comprehensive testing

For enterprise deployment, consider implementing the optional enhancements listed above.