diff --git a/apps/docs/docs/ref/server/usage-examples.mdx b/apps/docs/docs/ref/server/usage-examples.mdx new file mode 100644 index 00000000000..416a6461d44 --- /dev/null +++ b/apps/docs/docs/ref/server/usage-examples.mdx @@ -0,0 +1,98 @@ +--- +id: usage-examples +title: Usage examples +--- + +Each example is a Fetch handler. Deno, Bun, and Supabase Edge Functions run the `export default { fetch }` shape as is. Cloudflare Workers also need the `nodejs_compat` flag or the `env` option, so `withSupabase` can read your project's URL and keys. On Node, use an adapter or the primitives with your framework. + +### Protect an endpoint with a user JWT + + + + + `withSupabase` wraps your handler. With `auth: 'user'`, it checks the caller's JWT before your handler runs. A request without valid credentials gets a JSON error response, and your handler never runs. + + `withSupabase` also answers every `OPTIONS` request with `204` and adds CORS headers to every response. Set `cors: 'disabled'` when your framework handles CORS. + + `ctx.supabase` is scoped to the caller, so Row Level Security policies apply. `ctx.supabaseAdmin` bypasses RLS. Use it only for work that needs full database access. + + + + + + ```ts + import { withSupabase } from '@supabase/server' + + export default { + fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { + const { data } = await ctx.supabase.from('todos').select() + return Response.json(data) + }), + } + ``` + + + + +### Serve a public endpoint + + + + + `auth: 'none'` lets every request through. `ctx.userClaims` is `null`, and `ctx.supabase` runs as an anonymous client. + + Supabase Edge Functions check for a valid JWT on every request by default. For a function that uses `auth: 'none'`, `auth: 'publishable'`, or `auth: 'secret'`, turn that check off in `supabase/config.toml`. The `auth` setting on `withSupabase` then decides who gets in. + + + + + + ```ts + import { withSupabase } from '@supabase/server' + + export default { + fetch: withSupabase({ auth: 'none' }, async () => { + return Response.json({ status: 'ok', time: new Date().toISOString() }) + }), + } + ``` + + ```toml supabase/config.toml + [functions.my-function] + verify_jwt = false + ``` + + + + +### Build the context yourself + + + + + `createSupabaseContext` runs the same auth checks as `withSupabase` but returns `{ data, error }` instead of a response. Use it inside a framework route handler, or anywhere you want to shape the error response yourself. + + On success, `data` is the same `SupabaseContext` that `withSupabase` passes to your handler. On failure, `error.status` holds the HTTP status to send. `createSupabaseContext` does not handle CORS. + + + + + + ```ts + import { createSupabaseContext } from '@supabase/server' + + export default { + fetch: async (req: Request) => { + const { data: ctx, error } = await createSupabaseContext(req, { auth: 'user' }) + if (error) { + return Response.json(error.toJSON(), { status: error.status }) + } + + const { data } = await ctx.supabase.from('todos').select() + return Response.json(data) + }, + } + ``` + + + diff --git a/apps/docs/spec/reference/server/v1/config.json b/apps/docs/spec/reference/server/v1/config.json index dc086ebe58f..38d8544d106 100644 --- a/apps/docs/spec/reference/server/v1/config.json +++ b/apps/docs/spec/reference/server/v1/config.json @@ -1,5 +1,5 @@ { "categoryOrder": ["Middleware", "Primitives", "Adapters", "Errors", "Types"], - "partialsOrder": ["introduction", "installing"], + "partialsOrder": ["introduction", "installing", "usage-examples"], "navigationPrefixes": {} } diff --git a/apps/docs/spec/reference/server/v1/partials/usage-examples.mdx b/apps/docs/spec/reference/server/v1/partials/usage-examples.mdx new file mode 100644 index 00000000000..416a6461d44 --- /dev/null +++ b/apps/docs/spec/reference/server/v1/partials/usage-examples.mdx @@ -0,0 +1,98 @@ +--- +id: usage-examples +title: Usage examples +--- + +Each example is a Fetch handler. Deno, Bun, and Supabase Edge Functions run the `export default { fetch }` shape as is. Cloudflare Workers also need the `nodejs_compat` flag or the `env` option, so `withSupabase` can read your project's URL and keys. On Node, use an adapter or the primitives with your framework. + +### Protect an endpoint with a user JWT + + + + + `withSupabase` wraps your handler. With `auth: 'user'`, it checks the caller's JWT before your handler runs. A request without valid credentials gets a JSON error response, and your handler never runs. + + `withSupabase` also answers every `OPTIONS` request with `204` and adds CORS headers to every response. Set `cors: 'disabled'` when your framework handles CORS. + + `ctx.supabase` is scoped to the caller, so Row Level Security policies apply. `ctx.supabaseAdmin` bypasses RLS. Use it only for work that needs full database access. + + + + + + ```ts + import { withSupabase } from '@supabase/server' + + export default { + fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { + const { data } = await ctx.supabase.from('todos').select() + return Response.json(data) + }), + } + ``` + + + + +### Serve a public endpoint + + + + + `auth: 'none'` lets every request through. `ctx.userClaims` is `null`, and `ctx.supabase` runs as an anonymous client. + + Supabase Edge Functions check for a valid JWT on every request by default. For a function that uses `auth: 'none'`, `auth: 'publishable'`, or `auth: 'secret'`, turn that check off in `supabase/config.toml`. The `auth` setting on `withSupabase` then decides who gets in. + + + + + + ```ts + import { withSupabase } from '@supabase/server' + + export default { + fetch: withSupabase({ auth: 'none' }, async () => { + return Response.json({ status: 'ok', time: new Date().toISOString() }) + }), + } + ``` + + ```toml supabase/config.toml + [functions.my-function] + verify_jwt = false + ``` + + + + +### Build the context yourself + + + + + `createSupabaseContext` runs the same auth checks as `withSupabase` but returns `{ data, error }` instead of a response. Use it inside a framework route handler, or anywhere you want to shape the error response yourself. + + On success, `data` is the same `SupabaseContext` that `withSupabase` passes to your handler. On failure, `error.status` holds the HTTP status to send. `createSupabaseContext` does not handle CORS. + + + + + + ```ts + import { createSupabaseContext } from '@supabase/server' + + export default { + fetch: async (req: Request) => { + const { data: ctx, error } = await createSupabaseContext(req, { auth: 'user' }) + if (error) { + return Response.json(error.toJSON(), { status: error.status }) + } + + const { data } = await ctx.supabase.from('todos').select() + return Response.json(data) + }, + } + ``` + + +