Authentication
The OAuth 2.1 flow for agents acting as a user, API keys for headless server-to-server access, and why every call is bound by the same RLS.
Passo authenticates in two ways, for two kinds of caller. OAuth 2.1 is for a person connecting an agent: you approve it in the browser and from then on it acts as you, with no shared secret to store. API keys are for a backend calling Passo from a server or cron job with no human in the loop — a workspace admin mints a key and the caller presents it as a bearer token. Most of this page is the OAuth flow; API keys are at the end.
OAuth works because Passo's authorization server is Supabase's OAuth 2.1 server. The token a client ends up with is an ordinary Supabase user session — the same kind the dashboard holds — so every read and write runs under the same row-level-security policies. That is the whole security model, and it is worth stating plainly:
An agent sees only what its human can
The token carries the user's identity. Every query a tool or endpoint runs is filtered by the same RLS policies as the dashboard, keyed on that identity. An agent cannot read a workspace you are not a member of, or change a video you could not change yourself — not by policy we remember to apply, but because the database enforces it on every row.
The flow
You rarely drive this by hand — an MCP client does it for you — but end to end it is standard OAuth 2.1 with PKCE:
Discovery
The client fetches the server's protected-resource metadata, which points it at
Passo's authorization server (the Supabase project's /auth/v1). From there it
reads the authorization-server metadata to find the authorization, token, and
registration endpoints.
Dynamic registration
Passo has dynamic client registration enabled (RFC 7591), so a client registers itself from the server URL alone — no pre-provisioned client ID. This is what lets Claude add Passo from just the endpoint you paste in.
Consent
The client opens your browser to the Passo consent screen. It names the client requesting access and the account you are signed in as, and asks you to allow or deny. If you are not signed in, you sign in first and land back here. Approving redirects the client back with an authorization code.
Token exchange
The client exchanges the code (with its PKCE verifier) for an access token and
a refresh token. The access token is a Supabase JWT carrying your user id,
role, and the client id. The client sends it as Authorization: Bearer <token>
on every request.
Tokens and refresh
Access tokens are short-lived — Supabase issues them with a one-hour lifetime by default. Refresh tokens are long-lived and rotate on each use. A well-behaved MCP client refreshes silently in the background, so you approve consent once and do not see it again unless you disconnect the client or revoke access.
You do not manage any of this in normal use. If you are integrating a client that does not handle OAuth for you, follow its documentation for the standard authorization-code-with-PKCE and refresh-token grants against the discovery endpoints above.
Scopes
The OAuth scopes Supabase issues — openid, email, profile, phone —
control only what identity claims land in your ID token. They do not gate table
access. What an agent can touch is decided entirely by RLS on your user, not by
scopes. This is why read-only access is a separate
MCP endpoint rather than a scope you withhold at consent.
API keys
OAuth covers a person connecting an agent. It does not cover a backend that calls Passo from a server or cron job with no human present to approve consent — that is what an API key is for. A key belongs to one workspace and carries a role; every request it makes runs under that workspace role's RLS, exactly as a member of that role would. The same "an agent sees only what its human can" guarantee holds, keyed on the workspace and role instead of a user.
Mint a key
In the Passo dashboard, open Settings → API keys for the workspace and choose Create key. Only a workspace admin can mint or revoke keys. Give the key a name — so you can tell your keys apart later — and the role it should act as.
Copy the secret once
The full key — passo_… — is shown exactly once, on creation. Passo stores
only a hash of it, so it can never be retrieved again; copy it straight into your
secret store. If you lose it, revoke it and mint another.
Present it as a bearer token
Send the key in the Authorization header on every request — the same header an
OAuth token uses:
curl https://api.passo.co/v1/me \ -H "Authorization: Bearer passo_…"Revoke a key from the same Settings → API keys list at any time; once revoked it can no longer authenticate. Keys you mint here do not expire on their own — revoking is how you retire one.
MCP is OAuth-only
API keys authenticate the REST API. The MCP server does not accept them: the MCP spec mandates OAuth 2.1, so connect MCP clients with the connection guide above. A key is for headless HTTP, not for MCP.
Getting access
The MCP server is public today — connect any client by following the connection guide.
The REST API is built and documented but published on request. If you need direct HTTP access rather than MCP, get in touch and we will enable it for your account. Once it is on, you authenticate with either an OAuth token or an API key. The API reference documents every endpoint in the meantime.