/authorize, /token, client registration and the consent screen all belong to Supabase, whose OAuth 2.1 server handles them.
The flow
1
The client calls /mcp with no token
It gets a That header is the entire discovery mechanism. A bare
401 carrying a WWW-Authenticate header:401 would be a dead end, and the connect flow would die with nothing to show you.2
The client reads the metadata
RFC 9728. Served unauthenticated by necessity — the client reads it because it does not have a token.
authorization_servers is the only load-bearing field. Both the root and the path-suffixed well-known paths answer, since clients probe either.3
The client registers and sends you to authorize
Dynamic client registration, then the authorization-code flow with PKCE, all handled by Supabase.
4
You approve on the consent screen
In the MCPulse dashboard, at
/oauth/consent. One decision, no navigation around it.5
The client gets a token
An access token and — because
offline_access is requested — a refresh token.offline_access is the scope that is easy to leave out and expensive to. Without it no refresh token is issued, the access token expires after an hour, and the connection dies — presenting as Claude spontaneously losing access to MCPulse once an hour and needing re-approval.What a token is checked for
The signature check is the same one the REST API does — same project, same JWKS, sameES256. What differs is the audience.
A token must:
- be signed by the Supabase project and verify against its JWKS
- carry the expected issuer
- carry an audience of either this resource’s URL or
authenticated - have a
subclaim - have an
expclaim — a token with no expiry cannot be revoked by waiting
Why authenticated is accepted
Supabase does not implement RFC 8707. Its authorize endpoint takes no resource parameter, and every access token it issues — OAuth or browser session alike — carries aud: "authenticated".
So accepting that audience is not a testing convenience; it is the only path that authenticates anything. Tightening it to require the resource URL would lock every real client out, which is worth knowing before anyone “fixes” it.
The cost, stated plainly: audience alone cannot distinguish a token issued for MCPulse from any other token this project mints. Today that is a distinction without a difference — the project serves one product, and a token only exists after a human approved it on our own consent screen. It would stop being harmless the day this project issued tokens for a second purpose, and the fix then is a scope or client allow-list, not a wider audience check.
What is still refused is a token addressed to a different resource entirely — the confused-deputy case — which costs nothing to keep.