Authentication
Every request is made as a user. Contentpipe uses Supabase Auth as its authorization server, and RLS keys off the resulting JWT — so what you can read and write is exactly what that user can.
Two credentials, always
| Header | Value | Why |
|---|---|---|
apikey | the project publishable (anon) key | identifies the Supabase project; safe to ship in a client |
Authorization | Bearer <user access token> | identifies the user; RLS reads this |
The publishable key alone grants nothing — without a user token, RLS returns empty sets.
Getting a user token
Email / password
For scripts and tests, exchange credentials for a token at the token endpoint:
curl -X POST "https://jionfqfmjinkrmzlsghf.supabase.co/auth/v1/token?grant_type=password" \
-H "apikey: $CP_PUBLISHABLE_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"…"}'
The response contains an access_token (a normal Supabase JWT) and a refresh_token. Use the access token as the bearer above.
Password grant is the currently usable method — use a disposable, project-scoped account you control (create one per project rather than sharing a single cross-project login).
OAuth 2.1 (for AI clients)
Supabase Auth is enabled as a full OAuth 2.1 authorization server with dynamic client registration, so connectors like Claude and ChatGPT self-onboard. GitHub and Google are the configured identity providers, but their app credentials aren't live yet — until they land, email/password is the only usable sign-in (see MCP authentication).
The consent and login screens live in the Contentpipe web app: Supabase redirects to /oauth/consent?authorization_id=…, which round-trips through /login if there's no session, then approves or denies the grant. The important part for API consumers: an OAuth-issued token is an ordinary Supabase JWT — it works everywhere a password token works, including REST, RPCs, and MCP.
This flow is what the MCP server's authentication is built on. If you're connecting an AI client, start there.
Token as user identity
Because the token is the user, there's no service-role escape hatch on the public surfaces:
- REST and RPC calls run with the caller's RLS.
- The MCP server passes your token straight through to Postgres — it never uses the service role.
Keep tokens short-lived and refresh them with the refresh_token; treat them like passwords.