Skip to content

Commit 2d666bd

Browse files
HMarzbanclaude
andcommitted
docs(mcp): scope the Supabase token gate and name the password hook
The MCP reference said that Supabase refuses a connected app's token, with no limit. The gate covers only the Data API, Storage and Realtime. The Supabase Auth API has no client_id check. The reference now names those three surfaces. It also points to the password sign-in hook, which refuses every password sign-in. The local config.toml now sets secure_password_change = true. A running local stack takes it after a Supabase stop and start. The password hook stays commented out locally, because the e2e scripts and document-swarm sign in with a password. Refs #441 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8ecf60f commit 2d666bd

4 files changed

Lines changed: 17 additions & 3 deletions

File tree

‎apps/hocuspocus.server/CHANGELOG.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ SMTP_PASS=...
526526
Copies already in a browser cache stay until their one-year `immutable`
527527
entry expires. See Migration for existing objects.
528528

529-
- **Supabase refuses a connected app's token.** Run
529+
- **Supabase refuses a connected app's token on the Data API, Storage and Realtime.** Run
530530
`packages/supabase/scripts/31-connected-app-token-gate.sql` once, or push
531531
the paired migration `20260928120000_refuse_connected_app_tokens`. The Data
532532
API answers `403` with the code `connected_app`. Storage and Realtime refuse
@@ -545,6 +545,17 @@ SMTP_PASS=...
545545
[configuration](../../docs/self-hosting/configuration.md#turn-off-password-sign-in)
546546
says. It stays off on the local stack.
547547

548+
- **The MCP reference names what the Supabase gate covers ([#441](https://github.com/docs-plus/docs.plus/issues/441)).**
549+
[The reference](../../docs/mcp/reference.md#authorization) said that
550+
Supabase refuses a connected app's token, with no limit. The gate covers only
551+
the Data API, Storage and Realtime. The Supabase Auth API has no such check,
552+
so the reference now points to the password sign-in hook. In production, also
553+
turn on Secure password change, as
554+
[configuration](../../docs/self-hosting/configuration.md#turn-off-password-sign-in)
555+
says. The local `packages/supabase/config.toml` now sets
556+
`secure_password_change = true`. A running local stack takes it after a
557+
Supabase stop and start.
558+
548559
- **Outside development, `getErrorResponse` answers every 5xx with `Internal server error`.**
549560
The `code` is unchanged, and the server logs the original. A Prisma or
550561
Supabase message used to reach production `500` responses. A handler that

‎docs/mcp/reference.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ Replace `<PUBLIC_RESTAPI_URL>` with your server's value of [`PUBLIC_RESTAPI_URL`
2323
- Send the token as `Authorization: Bearer <token>`. Replace `<token>` with the access token the host gets at the end of the OAuth flow. The `token` header that other REST routes read is ignored here.
2424
- Only a token that carries a `client_id` claim is accepted. An OAuth grant adds that claim. A docs.plus browser session token never has it, so it gets `401`.
2525
- On the docs.plus server, only `/api/mcp` accepts a token with `client_id`. [Authentication](../api/authentication.md#what-each-credential-can-call) says what the other routes do with it.
26-
- The docs.plus Supabase project refuses a token with `client_id` too. The Data API (tables, RPC and GraphQL) answers `403` with the code `connected_app`. Storage shows the token no objects and refuses its uploads. Realtime refuses it on private channels, and applies the same refusal to database-change subscriptions. So build on the tools below, not on the Supabase APIs. A self-hosted server needs [one Supabase script](../self-hosting/configuration.md#turn-on-the-mcp-connector) for this.
26+
- The docs.plus Supabase project refuses a token with `client_id` on the Data API, Storage and Realtime. The Data API (tables, RPC and GraphQL) answers `403` with the code `connected_app`. Storage shows the token no objects and refuses its uploads. Realtime refuses it on private channels, and applies the same refusal to database-change subscriptions. So build on the tools below, not on the Supabase APIs. A self-hosted server needs [one Supabase script](../self-hosting/configuration.md#turn-on-the-mcp-connector) for this.
27+
- The Supabase Auth API has no `client_id` check. The [password sign-in hook](../self-hosting/configuration.md#turn-off-password-sign-in) refuses every password sign-in, so a password that a connected app sets cannot open a session. A self-hosted server must turn that hook on too.
2728

2829
**Audience binding is not possible today.** Supabase always sets `aud` to `authenticated`. It never writes the RFC 8707 `resource` into the token ([supabase/auth#2610](https://github.com/supabase/auth/issues/2610)). So `/api/mcp` cannot prove that a token was issued for it. The `client_id` rule is the strongest check Supabase allows.
2930

‎docs/self-hosting/configuration.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ The function is a Custom Access Token hook, which every Supabase plan has. It re
235235

236236
**Hosted Supabase.** In the Supabase dashboard, open **Authentication > Hooks**. Add the **Customize Access Token (JWT) Claims** hook, choose **Postgres**, and pick that function. The hook runs each time Supabase issues a token. If sign-in or a token refresh fails after you turn it on, turn the hook off again.
237237

238+
**Secure password change.** In the same dashboard, open the **Email** provider settings and turn on **Secure password change**. It asks for a recent sign-in before a password change. Supabase counts a session under 24 hours old as recent, so this setting is only an extra layer. The hook is the control that refuses a password sign-in.
239+
238240
**Local stack.** `packages/supabase/config.toml` has the hook block, commented out.
239241

240242
```toml

‎packages/supabase/config.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ double_confirm_changes = true
206206
# If enabled, users need to confirm their email address before signing in.
207207
enable_confirmations = false
208208
# If enabled, users will need to reauthenticate or have logged in recently to change their password.
209-
secure_password_change = false
209+
secure_password_change = true
210210
# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email.
211211
max_frequency = "1s"
212212
# Number of characters used in the email OTP.

0 commit comments

Comments
 (0)