# 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)