Skip to content

Commit 74b4b09

Browse files
committed
add supabase auth
Signed-off-by: phernandez <paul@basicmachines.co>
1 parent c13ffbc commit 74b4b09

4 files changed

Lines changed: 971 additions & 149 deletions

File tree

AUTH.md

Lines changed: 155 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,155 @@
1-
To test the built-in OAuth flow locally, here's what you need to do:
2-
3-
1. Set Environment Variables
4-
5-
First, create a .env file based on the example:
6-
7-
cp .env.oauth.example .env
8-
9-
Then edit .env to enable OAuth:
10-
11-
# Enable OAuth authentication
12-
FASTMCP_AUTH_ENABLED=true
13-
14-
# Use the basic (built-in) provider
15-
FASTMCP_AUTH_PROVIDER=basic
16-
17-
# OAuth issuer URL (your MCP server URL)
18-
FASTMCP_AUTH_ISSUER_URL=http://localhost:8000
19-
20-
2. Start the MCP Server with OAuth
21-
22-
Start the server using the streamable-http transport (OAuth works best with HTTP):
23-
24-
# Run with OAuth enabled
25-
FASTMCP_AUTH_ENABLED=true basic-memory mcp --transport streamable-http
26-
27-
# Or if you have the env vars in .env file:
28-
basic-memory mcp --transport streamable-http
29-
30-
You should see:
31-
OAuth authentication is ENABLED
32-
Issuer URL: http://localhost:8000
33-
34-
3. Register an OAuth Client
35-
36-
In a new terminal, register a test client:
37-
38-
basic-memory auth register-client
39-
40-
This will output something like:
41-
Client registered successfully!
42-
Client ID: AbCdEfGhIjKlMnOp
43-
Client Secret: QrStUvWxYz123456789...
44-
45-
Save these credentials!
46-
47-
4. Test the OAuth Flow
48-
49-
Run the built-in test command:
50-
51-
basic-memory auth test-auth
52-
53-
This will:
54-
1. Register a test client
55-
2. Generate an authorization URL
56-
3. Exchange the auth code for tokens
57-
4. Validate the access token
58-
59-
You'll see output like:
60-
Registered test client: ABC123...
61-
Authorization URL: http://localhost:3000/callback?code=XYZ&state=test-state
62-
Access token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
63-
Refresh token: QrStUvWxYz...
64-
Expires in: 3600 seconds
65-
Access token validated successfully!
66-
67-
5. Test with a Real Client
68-
69-
To test with an actual MCP client, you'll need to:
70-
71-
1. Make an authorization request:
72-
# Use the client_id from step 3
73-
curl "http://localhost:8000/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:3000/callback&response_type=code&code_challenge=test-challenge&code_challenge_method=S256"
74-
75-
2. Exchange the code for tokens:
76-
# Use the code from the redirect URL
77-
curl -X POST http://localhost:8000/token \
78-
-H "Content-Type: application/x-www-form-urlencoded" \
79-
-d "grant_type=authorization_code&code=YOUR_AUTH_CODE&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&code_verifier=test-verifier"
80-
81-
3. Use the access token to call MCP endpoints:
82-
curl http://localhost:8000/mcp \
83-
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
84-
85-
6. Quick Test Script
86-
87-
Here's a simple Python script to test the flow:
88-
89-
import httpx
90-
import asyncio
91-
from urllib.parse import urlparse, parse_qs
92-
93-
async def test_oauth():
94-
client = httpx.AsyncClient()
95-
96-
# Your client credentials
97-
client_id = "YOUR_CLIENT_ID"
98-
client_secret = "YOUR_CLIENT_SECRET"
99-
100-
# 1. Get authorization URL
101-
auth_response = await client.get(
102-
"http://localhost:8000/authorize",
103-
params={
104-
"client_id": client_id,
105-
"redirect_uri": "http://localhost:3000/callback",
106-
"response_type": "code",
107-
"code_challenge": "test-challenge",
108-
"code_challenge_method": "S256",
109-
}
110-
)
111-
112-
# Extract code from redirect
113-
redirect_url = auth_response.headers.get("Location")
114-
parsed = urlparse(redirect_url)
115-
code = parse_qs(parsed.query)["code"][0]
116-
117-
# 2. Exchange code for tokens
118-
token_response = await client.post(
119-
"http://localhost:8000/token",
120-
data={
121-
"grant_type": "authorization_code",
122-
"code": code,
123-
"client_id": client_id,
124-
"client_secret": client_secret,
125-
"code_verifier": "test-verifier",
126-
}
127-
)
128-
tokens = token_response.json()
129-
130-
# 3. Use access token
131-
mcp_response = await client.get(
132-
"http://localhost:8000/mcp",
133-
headers={"Authorization": f"Bearer {tokens['access_token']}"}
134-
)
135-
136-
print(f"MCP Response: {mcp_response.status_code}")
137-
138-
asyncio.run(test_oauth())
139-
140-
7. Debug Tips
141-
142-
- Check the server logs for OAuth-related messages
143-
- The basic provider stores everything in memory, so clients/tokens are lost on restart
144-
- You can modify the log level for more details:
145-
FASTMCP_AUTH_ENABLED=true basic-memory mcp --transport streamable-http
146-
147-
That's it! The built-in OAuth provider is perfect for local development and testing. For production, you'd want to use an external provider (GitHub/Google) or implement persistent storage for the basic provider.
1+
# OAuth Quick Start Guide
2+
3+
This guide shows how to quickly test OAuth authentication with Basic Memory MCP server.
4+
5+
## Local Testing with Built-in Provider
6+
7+
1. **Create `.env` file**:
8+
```bash
9+
cp .env.oauth.example .env
10+
```
11+
12+
2. **Enable OAuth** in `.env`:
13+
```bash
14+
FASTMCP_AUTH_ENABLED=true
15+
FASTMCP_AUTH_PROVIDER=basic
16+
```
17+
18+
3. **Start the server**:
19+
```bash
20+
# Using environment variables
21+
basic-memory mcp --transport streamable-http
22+
23+
# Or directly
24+
FASTMCP_AUTH_ENABLED=true basic-memory mcp --transport streamable-http
25+
```
26+
27+
4. **Register a client**:
28+
```bash
29+
basic-memory auth register-client
30+
# Save the client_id and client_secret!
31+
```
32+
33+
5. **Test the flow**:
34+
```bash
35+
basic-memory auth test-auth
36+
```
37+
38+
## Production with Supabase
39+
40+
1. **Create Supabase project** at [supabase.com](https://supabase.com)
41+
42+
2. **Configure `.env`**:
43+
```bash
44+
FASTMCP_AUTH_ENABLED=true
45+
FASTMCP_AUTH_PROVIDER=supabase
46+
SUPABASE_URL=https://your-project.supabase.co
47+
SUPABASE_ANON_KEY=your-anon-key
48+
SUPABASE_SERVICE_KEY=your-service-key
49+
```
50+
51+
3. **Start the server**:
52+
```bash
53+
basic-memory mcp --transport streamable-http
54+
```
55+
56+
## OAuth Endpoints
57+
58+
When OAuth is enabled, these endpoints are available:
59+
60+
- `GET /authorize` - OAuth authorization endpoint
61+
- `POST /token` - Token exchange endpoint
62+
- `GET /mcp` - Protected MCP endpoint (requires Bearer token)
63+
64+
## Testing with cURL
65+
66+
1. **Get authorization code**:
67+
```bash
68+
curl "http://localhost:8000/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:3000/callback&response_type=code&code_challenge=test"
69+
```
70+
71+
2. **Exchange for token**:
72+
```bash
73+
curl -X POST http://localhost:8000/token \
74+
-H "Content-Type: application/x-www-form-urlencoded" \
75+
-d "grant_type=authorization_code&code=AUTH_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET"
76+
```
77+
78+
3. **Use the token**:
79+
```bash
80+
curl http://localhost:8000/mcp \
81+
-H "Authorization: Bearer ACCESS_TOKEN"
82+
```
83+
84+
## Quick Test Script
85+
86+
```python
87+
import httpx
88+
import asyncio
89+
from urllib.parse import urlparse, parse_qs
90+
91+
async def test_oauth():
92+
# Your client credentials
93+
client_id = "YOUR_CLIENT_ID"
94+
client_secret = "YOUR_CLIENT_SECRET"
95+
96+
async with httpx.AsyncClient() as client:
97+
# 1. Get authorization URL
98+
auth_response = await client.get(
99+
"http://localhost:8000/authorize",
100+
params={
101+
"client_id": client_id,
102+
"redirect_uri": "http://localhost:3000/callback",
103+
"response_type": "code",
104+
"code_challenge": "test-challenge",
105+
"code_challenge_method": "S256",
106+
}
107+
)
108+
109+
# Extract code from redirect
110+
redirect_url = auth_response.headers.get("Location")
111+
parsed = urlparse(redirect_url)
112+
code = parse_qs(parsed.query)["code"][0]
113+
114+
# 2. Exchange code for tokens
115+
token_response = await client.post(
116+
"http://localhost:8000/token",
117+
data={
118+
"grant_type": "authorization_code",
119+
"code": code,
120+
"client_id": client_id,
121+
"client_secret": client_secret,
122+
"code_verifier": "test-verifier",
123+
}
124+
)
125+
tokens = token_response.json()
126+
127+
# 3. Use access token
128+
mcp_response = await client.get(
129+
"http://localhost:8000/mcp",
130+
headers={"Authorization": f"Bearer {tokens['access_token']}"}
131+
)
132+
133+
print(f"MCP Response: {mcp_response.status_code}")
134+
135+
asyncio.run(test_oauth())
136+
```
137+
138+
## Provider Options
139+
140+
- **basic**: Built-in provider (development only)
141+
- **supabase**: Supabase Auth (recommended for production)
142+
- **github**: GitHub OAuth
143+
- **google**: Google OAuth
144+
145+
## Debug Tips
146+
147+
- Check server logs for OAuth messages
148+
- Basic provider stores in memory (lost on restart)
149+
- Enable debug logging: `export FASTMCP_LOG_LEVEL=DEBUG`
150+
151+
## Documentation
152+
153+
- [OAuth Authentication Guide](docs/OAuth%20Authentication.md)
154+
- [Supabase OAuth Setup](docs/Supabase%20OAuth%20Setup.md)
155+
- [MCP Authorization Spec](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization)

0 commit comments

Comments
 (0)