mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
020957cd76
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude <noreply@anthropic.com>
259 lines
7.4 KiB
Markdown
259 lines
7.4 KiB
Markdown
# OAuth Authentication Guide
|
|
|
|
Basic Memory MCP server supports OAuth 2.1 authentication for secure access control. This guide covers setup, testing, and production deployment.
|
|
|
|
## Quick Start
|
|
|
|
### 1. Enable OAuth
|
|
|
|
```bash
|
|
# Set environment variable
|
|
export FASTMCP_AUTH_ENABLED=true
|
|
|
|
# Or use .env file
|
|
echo "FASTMCP_AUTH_ENABLED=true" >> .env
|
|
```
|
|
|
|
### 2. Start the Server
|
|
|
|
```bash
|
|
basic-memory mcp --transport streamable-http
|
|
```
|
|
|
|
### 3. Test with MCP Inspector
|
|
|
|
Since the basic auth provider uses in-memory storage with per-instance secret keys, you'll need to use a consistent approach:
|
|
|
|
#### Option A: Use Environment Variable for Secret Key
|
|
|
|
```bash
|
|
# Set a fixed secret key for testing
|
|
export FASTMCP_AUTH_SECRET_KEY="your-test-secret-key"
|
|
|
|
# Start the server
|
|
FASTMCP_AUTH_ENABLED=true basic-memory mcp --transport streamable-http
|
|
|
|
# In another terminal, register a client
|
|
basic-memory auth register-client --client-id=test-client
|
|
|
|
# Get a token using the same secret key
|
|
basic-memory auth test-auth
|
|
```
|
|
|
|
#### Option B: Use the Built-in Test Endpoint
|
|
|
|
```bash
|
|
# Start server with OAuth
|
|
FASTMCP_AUTH_ENABLED=true basic-memory mcp --transport streamable-http
|
|
|
|
# Register a client and get token in one step
|
|
curl -X POST http://localhost:8000/register \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"client_metadata": {"client_name": "Test Client"}}'
|
|
|
|
# Use the returned client_id and client_secret
|
|
curl -X POST http://localhost:8000/token \
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
-d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
|
|
```
|
|
|
|
### 4. Configure MCP Inspector
|
|
|
|
1. Open MCP Inspector
|
|
2. Configure:
|
|
- Server URL: `http://localhost:8000/mcp/` (note the trailing slash!)
|
|
- Transport: `streamable-http`
|
|
- Custom Headers:
|
|
```
|
|
Authorization: Bearer YOUR_ACCESS_TOKEN
|
|
Accept: application/json, text/event-stream
|
|
```
|
|
|
|
## OAuth Endpoints
|
|
|
|
The server provides these OAuth endpoints automatically:
|
|
|
|
- `GET /authorize` - Authorization endpoint
|
|
- `POST /token` - Token exchange endpoint
|
|
- `GET /.well-known/oauth-authorization-server` - OAuth metadata
|
|
- `POST /register` - Client registration (if enabled)
|
|
- `POST /revoke` - Token revocation (if enabled)
|
|
|
|
## OAuth Flow
|
|
|
|
### Standard Authorization Code Flow
|
|
|
|
1. **Get Authorization Code**:
|
|
```bash
|
|
curl "http://localhost:8000/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8000/callback&response_type=code&code_challenge=YOUR_CHALLENGE&code_challenge_method=S256"
|
|
```
|
|
|
|
2. **Exchange Code for Token**:
|
|
```bash
|
|
curl -X POST http://localhost:8000/token \
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
-d "grant_type=authorization_code&code=AUTH_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&code_verifier=YOUR_VERIFIER"
|
|
```
|
|
|
|
3. **Use Access Token**:
|
|
```bash
|
|
curl http://localhost:8000/mcp \
|
|
-H "Authorization: Bearer ACCESS_TOKEN"
|
|
```
|
|
|
|
## Production Deployment
|
|
|
|
### Using Supabase Auth
|
|
|
|
For production, use Supabase for persistent auth storage:
|
|
|
|
```bash
|
|
# Configure environment
|
|
FASTMCP_AUTH_ENABLED=true
|
|
FASTMCP_AUTH_PROVIDER=supabase
|
|
SUPABASE_URL=https://your-project.supabase.co
|
|
SUPABASE_ANON_KEY=your-anon-key
|
|
SUPABASE_SERVICE_KEY=your-service-key
|
|
|
|
# Start server
|
|
basic-memory mcp --transport streamable-http --host 0.0.0.0
|
|
```
|
|
|
|
### Security Requirements
|
|
|
|
1. **HTTPS Required**: OAuth requires HTTPS in production (localhost exception for testing)
|
|
2. **PKCE Support**: Claude.ai requires PKCE for authorization
|
|
3. **Token Expiration**: Access tokens expire after 1 hour
|
|
4. **Scopes**: Supported scopes are `read`, `write`, and `admin`
|
|
|
|
## Connecting from Claude.ai
|
|
|
|
1. **Deploy with HTTPS**:
|
|
```bash
|
|
# Use ngrok for testing
|
|
ngrok http 8000
|
|
|
|
# Or deploy to cloud provider
|
|
```
|
|
|
|
2. **Configure in Claude.ai**:
|
|
- Go to Settings → Integrations
|
|
- Click "Add More"
|
|
- Enter: `https://your-server.com/mcp`
|
|
- Click "Connect"
|
|
- Authorize in the popup window
|
|
|
|
## Debugging
|
|
|
|
### Common Issues
|
|
|
|
1. **401 Unauthorized**:
|
|
- Check token is valid and not expired
|
|
- Verify secret key consistency
|
|
- Ensure bearer token format: `Authorization: Bearer TOKEN`
|
|
|
|
2. **404 on Auth Endpoints**:
|
|
- Endpoints are at root, not under `/auth`
|
|
- Use `/authorize` not `/auth/authorize`
|
|
|
|
3. **Token Validation Fails**:
|
|
- Basic provider uses in-memory storage
|
|
- Tokens don't persist across server restarts
|
|
- Use same secret key for testing
|
|
|
|
### Debug Commands
|
|
|
|
```bash
|
|
# Check OAuth metadata
|
|
curl http://localhost:8000/.well-known/oauth-authorization-server
|
|
|
|
# Enable debug logging
|
|
export FASTMCP_LOG_LEVEL=DEBUG
|
|
|
|
# Test token directly
|
|
curl http://localhost:8000/mcp \
|
|
-H "Authorization: Bearer YOUR_TOKEN" \
|
|
-v
|
|
```
|
|
|
|
## Provider Options
|
|
|
|
- **basic**: In-memory storage (development only)
|
|
- **supabase**: Recommended for production
|
|
- **github**: GitHub OAuth integration
|
|
- **google**: Google OAuth integration
|
|
|
|
## Example Test Script
|
|
|
|
```python
|
|
import httpx
|
|
import asyncio
|
|
from urllib.parse import urlparse, parse_qs
|
|
|
|
async def test_oauth_flow():
|
|
"""Test the full OAuth flow"""
|
|
client_id = "test-client"
|
|
client_secret = "test-secret"
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
# 1. Get authorization code
|
|
auth_response = await client.get(
|
|
"http://localhost:8000/authorize",
|
|
params={
|
|
"client_id": client_id,
|
|
"redirect_uri": "http://localhost:8000/callback",
|
|
"response_type": "code",
|
|
"code_challenge": "test-challenge",
|
|
"code_challenge_method": "S256",
|
|
"state": "test-state"
|
|
}
|
|
)
|
|
|
|
# Extract code from redirect URL
|
|
redirect_url = auth_response.headers.get("Location")
|
|
parsed = urlparse(redirect_url)
|
|
code = parse_qs(parsed.query)["code"][0]
|
|
|
|
# 2. Exchange for token
|
|
token_response = await client.post(
|
|
"http://localhost:8000/token",
|
|
data={
|
|
"grant_type": "authorization_code",
|
|
"code": code,
|
|
"client_id": client_id,
|
|
"client_secret": client_secret,
|
|
"code_verifier": "test-verifier",
|
|
"redirect_uri": "http://localhost:8000/callback"
|
|
}
|
|
)
|
|
|
|
tokens = token_response.json()
|
|
print(f"Access token: {tokens['access_token']}")
|
|
|
|
# 3. Test MCP endpoint
|
|
mcp_response = await client.post(
|
|
"http://localhost:8000/mcp",
|
|
headers={"Authorization": f"Bearer {tokens['access_token']}"},
|
|
json={"method": "initialize", "params": {}}
|
|
)
|
|
|
|
print(f"MCP Response: {mcp_response.status_code}")
|
|
|
|
asyncio.run(test_oauth_flow())
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| `FASTMCP_AUTH_ENABLED` | Enable OAuth authentication | `false` |
|
|
| `FASTMCP_AUTH_PROVIDER` | OAuth provider type | `basic` |
|
|
| `FASTMCP_AUTH_SECRET_KEY` | JWT signing key (basic provider) | Random |
|
|
| `FASTMCP_AUTH_ISSUER_URL` | OAuth issuer URL | `http://localhost:8000` |
|
|
| `FASTMCP_AUTH_REQUIRED_SCOPES` | Required scopes (comma-separated) | `read,write` |
|
|
|
|
## Next Steps
|
|
|
|
- [Supabase OAuth Setup](./Supabase%20OAuth%20Setup.md) - Production auth setup
|
|
- [External OAuth Providers](./External%20OAuth%20Providers.md) - GitHub, Google integration
|
|
- [MCP OAuth Specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) - Official spec |