Skip to main content

Overview

The folksbase API uses Supabase Auth for authentication. Clients obtain a JWT token from Supabase and pass it in the Authorization header on every request. The API validates the token server-side by calling supabase.auth.getUser(token). Authentication is not global — it’s applied per-route. Public endpoints like the health check and OpenAPI spec don’t require a token. All data endpoints (contacts, tags, imports, exports, settings, stats) do.

How It Works

  1. The client authenticates with Supabase using any supported method (email/password, magic link, OAuth)
  2. Supabase returns a JWT access token and a refresh token
  3. The client includes the access token in the Authorization header for API requests
  4. The API middleware validates the token by calling Supabase’s getUser endpoint
  5. If valid, the middleware extracts userId and workspaceId from the user metadata and attaches them to the request context

Passing the Token

Include the JWT in the Authorization header using the Bearer scheme:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  https://folksbase.onrender.com/api/contacts
The token must start with Bearer (note the space). Requests without a valid header receive a 401 response.

What the Middleware Extracts

When authentication succeeds, the middleware sets two values on the request context:
FieldSourceDescription
userIduser.idThe Supabase user ID (UUID)
workspaceIduser.user_metadata.workspace_idThe workspace this user belongs to
Route handlers access these via c.get('user'):
const { userId, workspaceId } = c.get('user');
Every data query is scoped to the workspaceId, which is how folksbase implements workspace-level multi-tenancy. A user can only access contacts, tags, imports, and exports within their own workspace.

Error Responses

StatusCodeWhen
401UNAUTHORIZEDMissing or malformed Authorization header
401UNAUTHORIZEDToken is invalid or expired
401UNAUTHORIZEDUser has no workspace_id in their metadata
All auth errors follow the standard error response format:
{
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired token"
}

Token Lifecycle

Supabase JWTs have a configurable expiry (default: 1 hour). The frontend uses Supabase’s client library which handles token refresh automatically. If you’re building a custom client:
  • Store both the access token and refresh token
  • Use the refresh token to obtain a new access token before the current one expires
  • Handle 401 responses by refreshing the token and retrying the request

Workspace Provisioning

When a new user signs up, a Supabase webhook fires to /api/webhooks. The webhook handler:
  1. Creates a workspace for the user
  2. Creates default settings for the workspace
  3. Stores the workspace_id in the user’s metadata
  4. Queues a welcome email (sent after email confirmation)
This is all automatic — the client doesn’t need to do anything beyond the initial sign-up.