Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MatthewSabia1/SubPirate-Pro/llms.txt

Use this file to discover all available pages before exploring further.

Overview

SubPirate Pro uses JWT (JSON Web Token) authentication powered by Supabase Auth. All API endpoints (except /health and /api/test) require a valid JWT token in the Authorization header.

Getting a JWT Token

Tokens are obtained through Supabase Auth authentication flows:

1. Sign In

Users authenticate via the frontend application, which uses Supabase Auth with PKCE flow:
  • Email/Password: Traditional email and password authentication
  • OAuth Providers: Google OAuth (additional providers can be configured)
The frontend manages the authentication flow automatically. Once authenticated, the JWT access token is available from the Supabase session.

2. Frontend Token Retrieval

In the frontend application, tokens are automatically retrieved and attached to requests using the secureFetch() utility:
import { secureFetch } from '@/lib/fetch';

// Automatically includes JWT token
const response = await secureFetch('/api/subscription');
const data = await response.json();
The secureFetch() function (from src/lib/fetch.ts) automatically:
  1. Retrieves the current Supabase session
  2. Extracts the access_token
  3. Adds it to the Authorization header

Authorization Header Format

Include the JWT token in the Authorization header using the Bearer scheme:
Authorization: Bearer <your-jwt-token>

Example Request

curl -X GET \
  http://localhost:8787/api/subscription \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json"

Token Validation

The API validates tokens using Supabase Auth’s getUser() method:
  1. Extract Token: The server extracts the Bearer token from the Authorization header
  2. Validate with Supabase: Token is validated against Supabase Auth
  3. Verify User: User information is extracted from the validated token
  4. Attach to Request: User data is attached to req.user for downstream handlers

Server-Side Implementation

From server.js:server.js:208-243:
async function requireAuth(req, res, next) {
  const token = getBearerToken(req);
  
  if (!token) {
    return res.status(401).json({ 
      error: 'Missing Authorization bearer token' 
    });
  }

  const { data, error } = await supabaseAuth.auth.getUser(token);
  
  if (error || !data?.user) {
    return res.status(401).json({ 
      error: 'Invalid or expired token' 
    });
  }

  req.user = data.user;
  req.accessToken = token;
  next();
}

Token Lifecycle

Expiration
string
JWT tokens expire after a configurable period (default: 1 hour). The frontend automatically handles token refresh using Supabase’s session management.
Refresh
string
When a token expires, Supabase automatically attempts to refresh it using the refresh token stored in the session. This happens transparently in the frontend.
Revocation
string
Tokens are immediately invalidated when a user signs out. The Supabase session is cleared, and subsequent API requests with the old token will fail with 401 Unauthorized.

Local Admin Bypass (Development Only)

For local development and testing, SubPirate Pro includes an admin bypass mechanism that allows API access without a Supabase session.
This feature is only available in development mode and is automatically disabled in production.

Enabling Local Admin Mode

Set these environment variables:
LOCAL_ADMIN_BYPASS=1
LOCAL_ADMIN_TOKEN=your-secret-dev-token
Or using VITE_ prefixes for frontend access:
VITE_LOCAL_ADMIN_BYPASS=1
VITE_LOCAL_ADMIN_TOKEN=your-secret-dev-token

How It Works

  1. Frontend: When enabled, secureFetch() uses the local admin token instead of retrieving a Supabase session:
    // From src/lib/fetch.ts:5-12
    if (isLocalAdminSessionActive()) {
      headers.set('Authorization', 
        `Bearer ${import.meta.env.VITE_LOCAL_ADMIN_TOKEN}`);
      return fetch(url, { ...options, headers });
    }
    
  2. Backend: The server recognizes the local admin token and creates a synthetic admin user:
    // From server.js:212-223
    if (localAdminEnabled && token === localAdminToken) {
      req.user = { 
        id: '00000000-0000-4000-8000-000000000000', 
        email: 'local-admin@localhost' 
      };
      req.isLocalAdmin = true;
      return next();
    }
    
  3. Database Access: Local admin requests use the Supabase service role client, which bypasses Row Level Security (RLS) policies:
    // From server.js:246-248
    function getAuthedSupabaseClient(req) {
      if (req?.isLocalAdmin) {
        return supabaseService; // Service role = bypass RLS
      }
      // ... regular user client
    }
    

Security Safeguards

Production Block
string
The server explicitly ignores LOCAL_ADMIN_BYPASS=1 in production:
// server.js:176-178
if (isProduction && localAdminBypassFlag === '1') {
  console.warn('LOCAL_ADMIN_BYPASS is ignored in production for security.');
}
Origin Validation
string
Even with local admin enabled, requests must come from allowed CORS origins (defaults to localhost/127.0.0.1 in dev).

Example Usage

# Set in .env
LOCAL_ADMIN_BYPASS=1
LOCAL_ADMIN_TOKEN=dev-secret-123

# Make request with local admin token
curl -X GET \
  http://localhost:8787/api/subscription \
  -H "Authorization: Bearer dev-secret-123" \
  -H "Content-Type: application/json"

Authentication Errors

Missing Token

{
  "error": "Missing Authorization bearer token"
}
Status Code: 401 Unauthorized Cause: No Authorization header present in the request Solution: Include the Bearer token in the header

Invalid or Expired Token

{
  "error": "Invalid or expired token"
}
Status Code: 401 Unauthorized Cause: Token is malformed, expired, or revoked Solution: Obtain a fresh token by re-authenticating

Configuration Error

{
  "error": "Supabase server auth is not configured. Set SUPABASE_URL and SUPABASE_ANON_KEY (or VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY)."
}
Status Code: 500 Internal Server Error Cause: Server environment variables are not configured Solution: Ensure SUPABASE_URL and SUPABASE_ANON_KEY are set on the server

User Context

Once authenticated, user information is available in the request context:
req.user.id
string
Unique user ID (UUID format)
req.user.email
string
User’s email address
req.accessToken
string
The JWT access token used for the request
req.isLocalAdmin
boolean
true if using local admin bypass (development only)

Best Practices

Token Storage: Never store JWT tokens in localStorage. The frontend uses Supabase’s built-in session management, which handles secure token storage automatically.
Token Refresh: Let Supabase handle token refresh automatically. The secureFetch() utility always retrieves the current session, ensuring you’re using fresh tokens.
Error Handling: Always handle 401 responses by redirecting users to the login page. This indicates their session has expired.
Never commit tokens: Ensure .env files are in .gitignore. Never commit actual JWT tokens or the LOCAL_ADMIN_TOKEN to version control.