Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
DEPRECATED: Replaced by mcp-app-builder. Previously used to build ChatGPT apps with interactive React widgets via mcp-use.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/authentication/supabase.md
1# Supabase Authentication23Setting up OAuth with Supabase's OAuth 2.1 server. Supabase hosts `/authorize`, `/token`, `/register`, and `.well-known` discovery on your Supabase project — the MCP server only verifies the resulting JWTs.45**You host the consent UI.** Supabase redirects the browser to a URL you configure, and your route uses the Supabase JS SDK to load authorization details, render sign-in + consent, and submit the decision back to Supabase. mcp-use is not involved in that step — follow Supabase's [OAuth Server — Getting Started guide](https://supabase.com/docs/guides/auth/oauth-server/getting-started).67**Learn more:** [Supabase OAuth Server — MCP Authentication](https://supabase.com/docs/guides/auth/oauth-server/mcp-authentication) · [Standalone starter template](https://github.com/mcp-use/mcp-oauth-supabase-template) · [Runnable example](https://github.com/mcp-use/mcp-use/tree/main/libraries/typescript/packages/mcp-use/examples/server/oauth/supabase)89> This targets Supabase's **OAuth 2.1 server** — a different feature from Supabase Auth's social logins. Enable it explicitly in the dashboard under **Authentication → OAuth Server**.1011---1213## Quick Start1415```typescript16import { MCPServer, oauthSupabaseProvider, object } from "mcp-use/server";1718const server = new MCPServer({19name: "my-server",20version: "1.0.0",21oauth: oauthSupabaseProvider(),22});2324server.tool(25{ name: "whoami", description: "Get authenticated user info" },26async (_args, ctx) =>27object({28userId: ctx.auth.user.userId,29email: ctx.auth.user.email,30})31);3233server.listen();34```3536With a `.env` file:3738```bash39MCP_USE_OAUTH_SUPABASE_PROJECT_ID=your-project-id40MCP_USE_OAUTH_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...41```4243JWT verification and `.well-known` passthrough are automatic. You still need to mount your own consent route (see [Hosting the consent UI](#hosting-the-consent-ui) below).4445---4647## Setup48491. Create (or select) a project in the [Supabase Dashboard](https://app.supabase.com/). Copy the **Project ID** from **Project Settings → General**.502. **Authentication → OAuth Server** — enable the OAuth 2.1 server and set the **consent screen URL** to the route your MCP server will host (e.g. `http://localhost:3000/auth/consent`). Supabase appends `?authorization_id=<uuid>` when redirecting users there.513. **Authentication → Sign In / Providers** — enable at least one sign-in method so users can authenticate before consenting:52- **Anonymous sign-ins** — one-click guest sessions, ideal for demos53- **Email + password**, **magic links**, or **OAuth providers** (Google, GitHub, etc.) — for real apps544. Copy the **publishable key** (`sb_publishable_...`) from **Project Settings → API Keys**. You'll use it in the consent UI and in any tool that calls Supabase REST APIs.5556---5758## Environment Variables5960| Variable | Required | Description |61|----------|----------|-------------|62| `MCP_USE_OAUTH_SUPABASE_PROJECT_ID` | Yes (hosted) | Your Supabase project ID. Used to derive `https://<id>.supabase.co`. |63| `MCP_USE_OAUTH_SUPABASE_URL` | Yes (self-hosted/local) | Explicit base URL — use for `supabase start` or self-hosted (e.g. `http://localhost:54321`). Overrides `PROJECT_ID` when both are set. |64| `MCP_USE_OAUTH_SUPABASE_PUBLISHABLE_KEY` | Recommended | Publishable key (`sb_publishable_...`) — used by the consent UI and any tools calling Supabase REST/APIs |65| `MCP_USE_OAUTH_SUPABASE_JWT_SECRET` | Only for legacy HS256 projects | JWT secret for HS256 verification |6667> New Supabase projects issue `sb_publishable_...` keys. Legacy projects using `anon` JWT keys still work, but prefer publishable keys going forward.6869### Finding Your Credentials7071- **Project ID**: Project Settings → **General** → Reference ID72- **Publishable key**: Project Settings → **API Keys**73- **JWT Secret** (legacy HS256 only): Project Settings → **JWT Settings** (Legacy)7475---7677## Configuration Options7879Zero-config (reads from env vars):8081```typescript82oauth: oauthSupabaseProvider()83```8485Explicit config (overrides env vars):8687```typescript88oauth: oauthSupabaseProvider({89projectId: "my-project-id",90// supabaseUrl: "http://localhost:54321", // self-hosted / local override91jwtSecret: process.env.MCP_USE_OAUTH_SUPABASE_JWT_SECRET, // legacy HS256 only92verifyJwt: process.env.NODE_ENV === "production",93scopesSupported: ["openid", "profile", "email"],94})95```9697| Option | Type | Default | Description |98|--------|------|---------|-------------|99| `projectId` | `string?` | env var | Supabase project ID — derives `https://<id>.supabase.co` |100| `supabaseUrl` | `string?` | env var | Explicit base URL for self-hosted or local Supabase. Takes precedence over `projectId` when set. |101| `jwtSecret` | `string?` | env var | JWT secret for HS256 tokens (legacy projects) |102| `verifyJwt` | `boolean?` | `true` | Set `false` to skip JWT verification (**development only**) |103| `scopesSupported` | `string[]?` | `["openid", "profile", "email"]` | Override advertised scopes |104105> One of `projectId` / `supabaseUrl` (or their env vars) is required. Use `supabaseUrl` for `supabase start` or any non-`supabase.co` deployment.106107---108109## JWT Signing: ES256 vs HS256110111The provider auto-detects the algorithm from the token header.112113- **ES256 (new projects)** — asymmetric signing via elliptic curve keys. The provider fetches the JWKS endpoint automatically. No `jwtSecret` needed.114- **HS256 (legacy projects)** — symmetric signing via a shared secret. Provide `MCP_USE_OAUTH_SUPABASE_JWT_SECRET` or `jwtSecret` in config.115116---117118## Hosting the consent UI119120Supabase redirects the browser to the consent screen URL you configured. Your route must:1211221. Sign the user in if they aren't already (anonymous, magic link, OAuth, etc. — whatever you enabled)1232. Use the Supabase JS SDK to load the authorization details for `authorization_id`1243. Render approve/deny UI1254. Submit the decision back to Supabase and redirect to the resulting URL126127Follow Supabase's [OAuth Server — Getting Started guide](https://supabase.com/docs/guides/auth/oauth-server/getting-started) for the canonical implementation. See the [runnable example](https://github.com/mcp-use/mcp-use/tree/main/libraries/typescript/packages/mcp-use/examples/server/oauth/supabase) for a wired-up version (look at `auth-routes.ts`).128129---130131## User Context132133Supabase populates these fields on `ctx.auth.user`:134135| Field | Type | Source |136|-------|------|--------|137| `userId` | `string` | `sub` or `user_id` claim |138| `email` | `string?` | `email` claim |139| `name` | `string?` | `user_metadata.name` or `user_metadata.full_name` |140| `username` | `string?` | `user_metadata.username` |141| `picture` | `string?` | `user_metadata.avatar_url` |142| `roles` | `string[]?` | `role` claim (e.g. `["authenticated"]`) |143| `permissions` | `string[]?` | Derived from AAL (e.g. `["aal:aal1"]`) |144| `aal` | `string?` | Authentication Assurance Level |145| `amr` | `array?` | Authentication Methods References |146| `session_id` | `string?` | Supabase session ID |147148---149150## Making Supabase API Calls151152Create a Supabase client scoped to the request using the user's access token so Row Level Security (RLS) policies see the caller as the authenticated user:153154```typescript155import { createClient } from "@supabase/supabase-js";156157server.tool(158{ name: "list-notes", description: "Fetch the user's notes" },159async (_args, ctx) => {160const supabase = createClient(161`https://${process.env.MCP_USE_OAUTH_SUPABASE_PROJECT_ID}.supabase.co`,162process.env.MCP_USE_OAUTH_SUPABASE_PUBLISHABLE_KEY!,163{164auth: {165persistSession: false,166autoRefreshToken: false,167detectSessionInUrl: false,168},169global: {170headers: { Authorization: `Bearer ${ctx.auth.accessToken}` },171},172}173);174175const { data, error: queryError } = await supabase.from("notes").select();176if (queryError) return error(`Failed to fetch notes: ${queryError.message}`);177178return object({ notes: data ?? [] });179}180);181```182183**Key point:** The `Authorization` header uses the user's access token (for RLS); the publishable key is passed to `createClient` for SDK/API access.184185---186187## Example `.env`188189```bash190# Required: Supabase project ID (Dashboard → Project Settings → General)191MCP_USE_OAUTH_SUPABASE_PROJECT_ID=your-project-id192193# Self-hosted / local override — point at `supabase start` or your own host.194# When set, this wins over PROJECT_ID. Omit on supabase.co.195# MCP_USE_OAUTH_SUPABASE_URL=http://localhost:54321196197# Recommended: Publishable key (Dashboard → Project Settings → API Keys)198# Used by the consent UI and by tools calling Supabase REST/APIs199MCP_USE_OAUTH_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...200201# Legacy HS256 projects only (Dashboard → Project Settings → JWT Settings)202# New projects use ES256 + JWKS — leave this unset203# MCP_USE_OAUTH_SUPABASE_JWT_SECRET=your-jwt-secret204```205206### Local Supabase (`supabase start`)207208```typescript209oauth: oauthSupabaseProvider({210supabaseUrl: "http://localhost:54321",211})212```213214The provider derives the issuer and JWKS endpoint from this URL — the local stack exposes `/auth/v1/.well-known/openid-configuration` out of the box, so no extra wiring is needed.215216---217218## Next Steps219220- **Auth overview** → [overview.md](overview.md)221- **WorkOS setup** → [workos.md](workos.md)222- **Auth0 setup** → [auth0.md](auth0.md)223- **Build tools** → [../server/tools.md](../server/tools.md)224