# Authentication Guide
How to authenticate with BuildStability's MCP server and API.
## Overview
BuildStability uses Supabase Auth for authentication. All API requests require a valid JWT (JSON Web Token) in the Authorization header.
## Getting Your Access Token
### Method 1: Copy Token (Easiest)
When API access is enabled for your business:
1. Go to **Business** → **Business Settings** → **API & Integrations**
2. Turn on **Enable API/MCP Access** if needed
3. Click **Copy Token** — your JWT is copied to the clipboard
Use it as `Authorization: Bearer <token>` in MCP, PostgREST, or any API client.
### Method 2: Browser / Local Storage (Quick Test)
1. Log in to BuildStability at https://buildstability.com/login
2. Open browser DevTools (F12) → Application → Local Storage
3. Find the key `sb-<project-id>-auth-token`
4. Copy the `access_token` value
### Method 3: Supabase Client (For Code)
```typescript
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!
);
// Sign in
const { data: { session }, error } = await supabase.auth.signInWithPassword({
email: 'your@email.com',
password: 'your-password'
});
// Get access token
const accessToken = session?.access_token;
```
### Method 4: API Login Endpoint
```bash
curl -X POST https://buildstability.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "your@email.com",
"password": "your-password"
}'
```
Response includes `access_token` and `refresh_token`.
## What a JWT Looks Like
A JWT has three base64url-encoded segments separated by dots: `header.payload.signature`. The header describes the algorithm; the payload holds claims (e.g. `sub`, `email`, `exp`); the signature ensures integrity. Tokens are usually 200–500+ characters.
Example format (always use your own from Copy Token—tokens are user-specific and expire in 1 hour):
```
eyJhbGciOiJIUzI1NiIsImtpZCI6InV2YkpJdUExNWpQeFBDdXAiLCJ0eXAiOiJKV1QifQ.eyJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTc2ODc5MzM3M31dLCJhcHBfbWV0YWRhdGEiOnsicHJvdmlkZXIiOiJlbWFpbCIsInByb3ZpZGVycyI6WyJlbWFpbCJdfSwiYXVkIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoibWF0dGNub3RlcysxMEBnbWFpbC5jb20iLCJleHAiOjE3Njg5MTkzNzAsImlhdCI6MTc2ODkxNTc3MCwiaXNfYW5vbnltb3VzIjpmYWxzZSwiaXNzIjoiaHR0cHM6Ly95eWJvdWlpc2xkcWl6Z2VldnFuYy5zdXBhYmFzZS5jby9hdXRoL3YxIiwicGhvbmUiOiIiLCJyb2xlIjoiYXV0aGVudGljYXRlZCIsInNlc3Npb25faWQiOiIwZGExMWFjZC1iMTA0LTRmNWUtODBhOC1mYmE5NzU0NjVjYzQiLCJzdWIiOiI3OTYzNzUwNS0xMmM4LTQyYzQtOTVmZi1kYTFhNWFlZmNjMmUiLCJ1c2VyX21ldGFkYXRhIjp7ImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJmaXJzdF9uYW1lIjoiTUFyY28iLCJsYXN0X25hbWUiOiJQb2xsbyJ9fQ.y5O4bfebJunfHq3GETKq3c-1R_KhlTkb7rM2QjJJ770
```
**What to do with it:** Put it in the `Authorization: Bearer <your-token>` header for MCP (`POST /api/mcp`), PostgREST, or any BuildStability API that uses JWT auth.
## Using the Token
### MCP Requests
```bash
curl -X POST https://api.buildstability.com/api/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{ ... }'
```
### Supabase PostgREST API Requests
**Important:** PostgREST uses the same JWT tokens - no database credentials are exposed.
```bash
curl -X GET "https://your-project.supabase.co/rest/v1/profiles?business_id=eq.{your-business-id}" \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
```
**Security Notes:**
- ✅ Uses your user JWT token (same as MCP)
- ✅ Row Level Security (RLS) automatically filters results to your business
- ✅ No database credentials required
- ✅ Rate limited by Supabase (separate from MCP limits)
**Using Supabase Client SDK:**
```typescript
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://your-project.supabase.co',
'YOUR_ANON_KEY',
{
global: {
headers: {
Authorization: `Bearer ${userAccessToken}`
}
}
}
);
// All queries automatically respect RLS policies
const { data, error } = await supabase
.from('appointments')
.select('*, client:profiles(*)')
.eq('business_id', yourBusinessId);
```
See the [PostgREST API Guide](/help/postgrest-api) for detailed usage examples.
## Token Expiration
Access tokens expire after 1 hour. Refresh tokens are valid for 30 days.
### Refreshing a Token
```typescript
const { data: { session }, error } = await supabase.auth.refreshSession({
refresh_token: storedRefreshToken
});
const newAccessToken = session?.access_token;
```
### Automatic Refresh (Supabase Client)
The Supabase client automatically refreshes tokens when they expire. Use the client's `onAuthStateChange` listener:
```typescript
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'TOKEN_REFRESHED') {
console.log('Token refreshed:', session?.access_token);
}
});
```
## Security Best Practices
### 1. Never Commit Tokens
```bash
# .gitignore
.env
*.token
secrets.json
```
### 2. Use Environment Variables
```typescript
const accessToken = process.env.BUILDSTABILITY_ACCESS_TOKEN;
```
### 3. Store Tokens Securely
- **Server-side**: Use environment variables or secret management (AWS Secrets Manager, etc.)
- **Client-side**: Use secure storage (not localStorage for sensitive apps)
- **Mobile**: Use Keychain (iOS) or Keystore (Android)
### 4. Rotate Tokens Regularly
If a token is compromised, revoke it immediately:
```typescript
await supabase.auth.signOut();
```
### 5. Use HTTPS Only
Always use `https://` endpoints. Never send tokens over HTTP.
## Multi-Tenancy & API Access
BuildStability uses business-level isolation with explicit API opt-in:
### Security Model
1. **API Access Must Be Enabled:** Your business administrator must enable API access before MCP endpoints work. This is a security measure.
2. **Business Isolation:** You can only access data for your business. All queries are automatically filtered by `business_id`.
3. **Multi-Business Support:** If you belong to multiple businesses, use the `X-Business-ID` header to specify which business to access.
### Enabling API Access
Business administrators can enable API access:
1. Go to **Business Settings** > **API & Integrations**
2. Toggle **Enable API Access** and save if needed
3. Click **Copy Token** to copy your JWT to the clipboard
### Multi-Business Users
If you belong to multiple businesses with API access enabled:
```bash
# Specify which business to access
curl -X POST https://api.buildstability.com/api/mcp \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "X-Business-ID: your-business-uuid" \
-H "Content-Type: application/json" \
-d '{ ... }'
```
Without the `X-Business-ID` header, the system uses your first API-enabled business.
## API Keys vs Access Tokens
- **Access Token (JWT)**: User-specific, expires after 1 hour. Use for MCP and authenticated API calls.
- **Anon Key**: Public, never expires. Use for unauthenticated Supabase queries (limited access).
For MCP, always use the **Access Token**.
## Troubleshooting
### "Business context required" Error
- Your token is missing or invalid
- Token has expired (refresh it)
- You're not authenticated
### "Invalid Request" Error
- Check your JSON-RPC format
- Verify `jsonrpc: "2.0"` is present
- Ensure `method` and `id` are included
### "Method not found" Error
- Check the method name spelling
- Verify you're using the correct endpoint (`/api/mcp`)
- Review available methods with `tools/list`
## Next Steps
- Read the [Quick Start Guide](/quickstart-mcp.md)
- Check out [Code Examples](/code-examples.md)
- Review the [Agent Integration Guide](/agents.md)