Files
AegisGitea-MCP/AUTH_SETUP.md
latte 0a2a21cc52 feat: scope query param auth to MCP endpoints
Restrict api_key query parameter to /mcp/tools, /mcp/tool/call,
and /mcp/sse only. Updated documentation to reflect query param
usage for ChatGPT UI without header support.
2026-01-29 21:07:37 +01:00

10 KiB

Authentication Setup Guide

This guide walks you through setting up API key authentication for AegisGitea MCP to ensure only your ChatGPT workspace can access your self-hosted Gitea instance.


Overview

AegisGitea MCP uses Bearer Token authentication to secure access:

  • API Keys: Cryptographically secure 64-character tokens
  • Header-based: Keys sent via Authorization: Bearer <key> header
  • Multi-key support: Multiple keys for rotation grace periods
  • Rate limiting: Failed auth attempts trigger IP-based rate limits
  • Audit logging: All auth attempts logged for security monitoring

Quick Start (5 minutes)

1. Generate API Key

# Using Make
make generate-key

# Or directly
python3 scripts/generate_api_key.py

This will:

  • Generate a secure 64-character API key
  • Show you the key (save it immediately!)
  • Provide .env configuration snippet
  • Optionally save metadata (not the key itself) for tracking

Example output:

✓ API Key Generated Successfully!

API KEY:
  a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2

📋 Next Steps:
1. Add this key to your .env file
2. Restart the MCP server
3. Configure ChatGPT Business

2. Add Key to .env

# Edit .env
nano .env

# Add/update this line:
MCP_API_KEYS=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2

3. Restart MCP Server

docker-compose restart aegis-mcp

# Verify authentication is enabled
docker-compose logs aegis-mcp | grep "authentication"

Expected log output:

API key authentication ENABLED (1 key(s) configured)

4. Test Authentication

# Without key - should fail with 401
curl https://mcp.yourdomain.com/mcp/tools

# With valid key (header) - should succeed
curl -H "Authorization: Bearer YOUR_KEY_HERE" \
     https://mcp.yourdomain.com/mcp/tools

# With valid key (query param) - should succeed
curl "https://mcp.yourdomain.com/mcp/tools?api_key=YOUR_KEY_HERE"

Configuration Options

Environment Variables

# Enable/disable authentication
AUTH_ENABLED=true              # Set to false ONLY for testing

# API keys (comma-separated for multiple)
MCP_API_KEYS=key1              # Single key
MCP_API_KEYS=key1,key2,key3    # Multiple keys (rotation grace period)

# Rate limiting
MAX_AUTH_FAILURES=5            # Max failed attempts before blocking
AUTH_FAILURE_WINDOW=300        # Time window in seconds (5 min)

Multiple Keys (Rotation Grace Period)

During key rotation, you can temporarily allow multiple keys:

# Old key
MCP_API_KEYS=old-key-here

# Add new key (both work)
MCP_API_KEYS=old-key-here,new-key-here

# After updating ChatGPT, remove old key
MCP_API_KEYS=new-key-here

Security Features

1. Constant-Time Comparison

Keys are compared using hmac.compare_digest() to prevent timing attacks.

2. Rate Limiting

  • Threshold: 5 failed attempts per IP
  • Window: 5 minutes (configurable)
  • Action: Reject all requests from that IP until window expires
  • Logging: High-severity security event logged

3. Audit Logging

Every authentication attempt logs:

{
  "timestamp": "2026-01-29T12:34:56.789Z",
  "event": "api_authentication",
  "status": "success",
  "client_ip": "203.0.113.42",
  "user_agent": "ChatGPT-User/1.0",
  "key_hint": "a1b2c3d4...e1f2"
}

Failed attempts:

{
  "timestamp": "2026-01-29T12:34:56.789Z",
  "event": "access_denied",
  "reason": "invalid_api_key",
  "client_ip": "203.0.113.42"
}

4. Key Format Validation

  • Minimum length: 32 characters
  • Recommended length: 64 characters
  • Format: Hexadecimal string (0-9, a-f)

Troubleshooting

Issue: "No API keys configured" error

Symptoms:

docker-compose logs: "No API keys configured in environment"

Solution:

  1. Check .env file exists and contains MCP_API_KEYS
  2. Ensure no typos (MCP_API_KEYS not MCP_API_KEY)
  3. Verify key is at least 32 characters
  4. Restart container after updating .env

Issue: "Invalid API key" on valid key

Possible causes:

  1. Whitespace in .env: Remove spaces around =

    # Wrong
    MCP_API_KEYS = key-here
    
    # Correct
    MCP_API_KEYS=key-here
    
  2. Key truncated: Ensure entire 64-char key is copied

    # Check key length
    echo -n "your-key-here" | wc -c
    # Should output: 64
    
  3. Container not restarted: Always restart after changing .env

    docker-compose restart aegis-mcp
    

Issue: Rate limit blocking legitimate requests

Symptoms:

"Too many failed authentication attempts"

Solution:

  1. Check audit logs for failed attempts:

    docker-compose exec aegis-mcp cat /var/log/aegis-mcp/audit.log | grep "invalid_api_key"
    
  2. Wait 5 minutes for rate limit to reset

  3. If accidentally blocked yourself:

    # Restart container (clears in-memory rate limits)
    docker-compose restart aegis-mcp
    
  4. Adjust rate limit settings in .env if needed:

    MAX_AUTH_FAILURES=10
    AUTH_FAILURE_WINDOW=600
    

Issue: ChatGPT can't connect after adding auth

See CHATGPT_SETUP.md for detailed ChatGPT configuration.

Quick check:

  1. Verify key in ChatGPT settings matches .env
  2. Check Authorization header format: Bearer <key> (with space)
  3. Test manually with curl first

Monitoring Authentication

View All Auth Attempts

# All auth events
docker-compose exec aegis-mcp grep "api_authentication" /var/log/aegis-mcp/audit.log

# Failed attempts only
docker-compose exec aegis-mcp grep "access_denied" /var/log/aegis-mcp/audit.log

# Rate limit triggers
docker-compose exec aegis-mcp grep "auth_rate_limit_exceeded" /var/log/aegis-mcp/audit.log

Real-Time Monitoring

# Follow auth events
docker-compose exec aegis-mcp tail -f /var/log/aegis-mcp/audit.log | grep "auth"

Weekly Summary Script

#!/bin/bash
# Save as scripts/auth_summary.sh

CONTAINER="aegis-gitea-mcp"
LOG_PATH="/var/log/aegis-mcp/audit.log"

echo "=== Weekly Auth Summary ==="
echo ""
echo "Total auth attempts:"
docker exec $CONTAINER grep "api_authentication" $LOG_PATH | wc -l

echo ""
echo "Successful:"
docker exec $CONTAINER grep "api_authentication.*success" $LOG_PATH | wc -l

echo ""
echo "Failed:"
docker exec $CONTAINER grep "access_denied.*invalid_api_key" $LOG_PATH | wc -l

echo ""
echo "Rate limited IPs:"
docker exec $CONTAINER grep "auth_rate_limit_exceeded" $LOG_PATH | wc -l

Best Practices

1. Key Storage

  • Store in .env file (never commit to git)
  • Use password manager for backup
  • Save key metadata (not key itself) for tracking
  • Never hardcode in application code
  • Never share via unencrypted channels

2. Key Rotation

  • Schedule: Every 90 days (automated check available)
  • Method: Use make rotate-key for guided rotation
  • Grace period: Temporarily allow both old and new keys
  • Verification: Test new key before removing old key

See KEY_ROTATION.md for detailed rotation procedures.

3. Access Control

  • Single workspace: One key for your ChatGPT Business account
  • Multiple users: One key per user (track with metadata)
  • Revocation: Remove key from .env and restart

4. Monitoring

  • Weekly: Review auth logs for anomalies
  • Monthly: Check key age with make check-key-age
  • Quarterly: Rotate keys
  • Alerts: Set up notifications for rate limit events

Advanced Configuration

Disable Authentication (Testing Only)

⚠️ WARNING: Only for isolated test environments

# .env
AUTH_ENABLED=false

Server will log critical warning:

API key authentication DISABLED - server is open to all requests!

Custom Rate Limiting

# More lenient (for high-traffic)
MAX_AUTH_FAILURES=20
AUTH_FAILURE_WINDOW=600  # 10 minutes

# More strict (for high-security)
MAX_AUTH_FAILURES=3
AUTH_FAILURE_WINDOW=1800  # 30 minutes

Key Hashing (Future Enhancement)

Currently keys are stored in plaintext in .env. Future versions will support hashed keys in database.

Current security model:

  • Keys never logged in full (only first 8 + last 4 chars)
  • .env file protected by filesystem permissions
  • Container runs as non-root user
  • ⚠️ Ensure .env has restrictive permissions: chmod 600 .env

Security Checklist

Before going to production:

  • API key generated with make generate-key (not manually typed)
  • Key is exactly 64 characters
  • .env file has restrictive permissions (chmod 600 .env)
  • .env is in .gitignore (verify: git status shows no .env)
  • Container restarted after adding key
  • Authentication enabled (check logs for "ENABLED" message)
  • Test curl command succeeds with key, fails without
  • ChatGPT configured with Authorization header
  • Rate limiting tested (try 6 failed attempts)
  • Audit logs capturing auth events
  • Key rotation reminder set (90 days)
  • Backup key stored securely (password manager)

FAQ

Q: Can I use the same key for multiple ChatGPT workspaces?

A: Yes, but not recommended. Generate separate keys for auditability:

MCP_API_KEYS=workspace1-key,workspace2-key

Q: How do I revoke access immediately?

A: Remove key from .env and restart:

# Edit .env (remove old key)
docker-compose restart aegis-mcp

Access is revoked instantly after restart.

Q: Does rate limiting affect valid keys?

A: No. Rate limiting only applies to IPs that fail authentication. Valid keys are never rate limited.

Q: Can I see which key was used for each request?

A: Yes. Audit logs include key_hint (first 8 + last 4 characters):

{"key_hint": "a1b2c3d4...e1f2"}

Q: What happens if I lose my API key?

A: Generate a new one with make generate-key, update .env, restart server, update ChatGPT config. The old key stops working immediately after restart.


Next Steps


Need help? Open an issue in the Gitea repository.