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.
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
.envconfiguration 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:
- Check
.envfile exists and containsMCP_API_KEYS - Ensure no typos (
MCP_API_KEYSnotMCP_API_KEY) - Verify key is at least 32 characters
- Restart container after updating
.env
Issue: "Invalid API key" on valid key
Possible causes:
-
Whitespace in .env: Remove spaces around
=# Wrong MCP_API_KEYS = key-here # Correct MCP_API_KEYS=key-here -
Key truncated: Ensure entire 64-char key is copied
# Check key length echo -n "your-key-here" | wc -c # Should output: 64 -
Container not restarted: Always restart after changing
.envdocker-compose restart aegis-mcp
Issue: Rate limit blocking legitimate requests
Symptoms:
"Too many failed authentication attempts"
Solution:
-
Check audit logs for failed attempts:
docker-compose exec aegis-mcp cat /var/log/aegis-mcp/audit.log | grep "invalid_api_key" -
Wait 5 minutes for rate limit to reset
-
If accidentally blocked yourself:
# Restart container (clears in-memory rate limits) docker-compose restart aegis-mcp -
Adjust rate limit settings in
.envif 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:
- Verify key in ChatGPT settings matches
.env - Check Authorization header format:
Bearer <key>(with space) - 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
.envfile (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-keyfor 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
.envand 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)
- ✅
.envfile protected by filesystem permissions - ✅ Container runs as non-root user
- ⚠️ Ensure
.envhas 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
.envfile has restrictive permissions (chmod 600 .env).envis in.gitignore(verify:git statusshows 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
- ChatGPT Setup Guide - Configure ChatGPT Business
- Key Rotation Guide - Automated rotation procedures
- Security Policy - Overall security best practices
Need help? Open an issue in the Gitea repository.