Skip to content

Supabase Authentication Setup

Status: Implemented ✅ | Configuration Needed ⚠️

Quick Links: - Supabase Dashboard: https://supabase.com/dashboard


Immediate Next Steps (Required for Deployment)

1. Get Supabase Service Key

Why: Backend needs service_role key for creating auth sessions

Steps: 1. Go to https://supabase.com/dashboard 2. Select your project 3. Click Settings (left sidebar) → API 4. Scroll to "Project API keys" 5. Copy the service_role secret key - ⚠️ Keep this secret! Never commit to git or share publicly - This key has full database access


2. Add Environment Variables to Railway

Add to BOTH Railway environments (dev and production):

# Supabase Authentication
SUPABASE_URL=https://<your-project>.supabase.co
SUPABASE_ANON_KEY=<your-anon-key>
SUPABASE_SERVICE_KEY=<paste-service-role-key-from-step-1>

# iMessage relay authentication (legacy /orchestrator/message)
RELAY_WEBHOOK_SECRET=<generate-random-secret>

How to add to Railway: 1. Go to Railway dashboard 2. Select your project → backend service 3. Click Variables tab 4. Click + New Variable 5. Add each variable above 6. Deploy (Railway will auto-redeploy)

Generate RELAY_WEBHOOK_SECRET:

# Option 1: Use openssl
openssl rand -hex 32

# Option 2: Use Python
python -c "import secrets; print(secrets.token_hex(32))"


3. Update Frontend Authentication

The web app (../archety-web) uses HTTP-only cookies (withCredentials: true) plus CSRF protection for mutating requests.

  • Session check: GET /auth/session
  • CSRF token: GET /auth/csrf-token
  • OTP verification: POST /auth/verify/start, POST /auth/verify/confirm

Avoid storing long-lived auth tokens in localStorage.


4. Update Mac Mini Relay

Add authentication to orchestrator requests:

import os

# Get secret from environment variable
RELAY_WEBHOOK_SECRET = os.getenv("RELAY_WEBHOOK_SECRET")

# Add to all requests to /orchestrator/message
headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {RELAY_WEBHOOK_SECRET}"
}

response = requests.post(
    "https://archety-backend-prod.up.railway.app/orchestrator/message",
    json=message_payload,
    headers=headers
)

5. Run Database Migrations

When deploying to production for the first time:

# Option 1: Via Railway CLI
railway run alembic upgrade head

# Option 2: One-time deploy script
# Add to Railway deployment command (if not auto-running)
alembic upgrade head && uvicorn app.main:app

What this does: - Creates user_traits table - Creates trait_profiles table - Creates onboarding_sessions table - Renames metadatameta_data in existing tables


Testing the Authentication

Test 1: Phone Verification Flow

# 1. Start verification
curl -X POST http://localhost:8000/auth/verify/start \
  -H "Content-Type: application/json" \
  -d '{"phone": "+15551234567"}'

# 2. Confirm with OTP (check your phone)
curl -X POST http://localhost:8000/auth/verify/confirm \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+15551234567",
    "code": "123456",
    "name": "Test User"
  }'

# Response includes:
# - access_token (use this!)
# - refresh_token
# - user_id

Test 2: Authenticated Endpoint

# Get user profile (requires auth)
curl -X GET http://localhost:8000/user/profile \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"

# Should return:
# - User profile data
# - Trait profile (if exists)
# - Relationship data

Test 3: Orchestrator Authentication

# Test orchestrator endpoint (requires relay secret)
curl -X POST http://localhost:8000/orchestrator/message \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_RELAY_SECRET_HERE" \
  -d '{
    "chat_guid": "test-123",
    "mode": "direct",
    "sender": "+15551234567",
    "text": "hello sage!",
    "timestamp": 1699123456,
    "participants": ["+15551234567"]
  }'

Current Status

✅ Implemented: - Supabase client wrapper (app/identity/supabase_client.py) - Authentication dependencies (app/dependencies.py) - JWT generation after Twilio OTP - All user endpoints secured - Orchestrator endpoint secured - Configuration added to app/config.py

⚠️ Configuration Needed: - [ ] Add SUPABASE_SERVICE_KEY to Railway - [ ] Add RELAY_WEBHOOK_SECRET to Railway - [ ] Update frontend to use access_token - [ ] Update Mac mini relay with auth header - [ ] Run database migrations

📝 Future Improvements: - [ ] Productionize: Separate Supabase projects for dev/prod (before launch) - [ ] Add token refresh endpoint (POST /auth/refresh) - [ ] Implement full HMAC signing for orchestrator (upgrade from Bearer token) - [ ] Add session revocation endpoint - [ ] Add "remember me" functionality (longer token expiry)


Production Readiness Checklist

Before launching to real users:

  • Separate Supabase Projects
  • Create new production project in Supabase
  • Update Railway prod environment with new keys
  • Keep dev environment with current keys
  • Test both environments independently

  • Security Hardening

  • Enable Supabase Row Level Security (RLS) policies
  • Set up Supabase auth rate limiting
  • Rotate all secrets (RELAY_WEBHOOK_SECRET, service keys)
  • Enable HTTPS-only cookies in production
  • Add webhook signature verification (upgrade to HMAC)

  • Monitoring

  • Set up Supabase auth analytics
  • Monitor JWT refresh rates
  • Alert on auth failure spikes
  • Track token expiry issues

Cost & Limits

Current Setup (Free Tier): - 50,000 Monthly Active Users (MAU) - 500 MB database storage - 2 GB bandwidth/month - Unlimited API requests

When to Upgrade ($25/month Pro): - Hit 50,000 MAU - Need more than 500 MB storage - Need custom SMTP for emails - Need point-in-time recovery

Scaling Path: - 0-50K users: Free tier ✅ - 50K-100K users: Pro tier (\(25/mo) - 100K+ users: Team tier (\)599/mo) or Enterprise


Troubleshooting

Issue: "Supabase not enabled" warning in logs

Cause: Environment variables not set

Fix: 1. Add SUPABASE_URL and SUPABASE_SERVICE_KEY to Railway 2. Redeploy backend 3. Check logs for "Supabase client initialized" message


Issue: 401 Unauthorized on /user/profile

Cause: Missing or invalid access token

Fix: 1. Verify frontend is sending Authorization: Bearer <token> header 2. Check token hasn't expired (tokens last 1 hour by default) 3. Verify token was obtained from /auth/verify/confirm 4. Check Supabase service key is correct


Issue: "Invalid signature" on /orchestrator/message

Cause: Missing or incorrect RELAY_WEBHOOK_SECRET

Fix: 1. Ensure RELAY_WEBHOOK_SECRET is set in Railway 2. Ensure Mac mini relay is sending same secret in Authorization header 3. Format: Authorization: Bearer <secret>


Support & Resources

Supabase Documentation: - Auth Guide: https://supabase.com/docs/guides/auth - Python Client: https://supabase.com/docs/reference/python/introduction - JWT Structure: https://supabase.com/docs/guides/auth/jwts

Project Files: - Implementation: app/identity/supabase_client.py - Dependencies: app/dependencies.py - Auth Routes: app/api/auth_routes.py - User Routes: app/api/user_routes.py - Config: app/config.py

Need Help? - Supabase Discord: https://discord.supabase.com - GitHub Issues: https://github.com/rawrjustin/archety/issues


Last Updated: November 13, 2025 Version: 1.0 - Initial Supabase Integration