diff --git a/apps/reference/docs/guides/functions.mdx b/apps/reference/docs/guides/functions.mdx index d32cfa12cf4..0391adce248 100644 --- a/apps/reference/docs/guides/functions.mdx +++ b/apps/reference/docs/guides/functions.mdx @@ -7,29 +7,6 @@ sidebar_label: Overview import Tabs from '@theme/Tabs' import TabItem from '@theme/TabItem' -import ButtonCard from '@site/src/components/ButtonCard' -const examples = [ - { - name: 'With supabase-js', - description: 'Use the Supabase client inside your Edge Function.', - href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/select-from-table-with-auth-rls/index.ts', - }, - { - name: 'With CORS headers', - description: 'Send CORS headers for invoking from the browser.', - href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts', - }, - { - name: 'React Native with Stripe', - description: 'Full example for using Supabase and Stripe, with Expo.', - href: 'https://github.com/supabase-community/expo-stripe-payments-with-supabase-functions', - }, - { - name: 'Flutter with Stripe', - description: 'Full example for using Supabase and Stripe, with Flutter.', - href: 'https://github.com/supabase-community/flutter-stripe-payments-with-supabase-functions', - }, -] Edge Functions are server-side TypeScript functions, distributed globally at the edge—close to your users. They can be used for listening to webhooks or integrating your Supabase project with third-parties [like Stripe](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks). @@ -235,26 +212,6 @@ To see all the secrets which you have set remotely, use [`supabase secrets list` supabase secrets list ``` -## Examples - -You can find a list of useful [Edge Function Examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) in our GitHub repository. - -
-
- {examples.map((x) => ( -
- -
- ))} -
-
- ## Suggestions ### Database Functions vs Edge Functions diff --git a/apps/reference/docs/guides/functions/auth.mdx b/apps/reference/docs/guides/functions/auth.mdx new file mode 100644 index 00000000000..615ed5484c7 --- /dev/null +++ b/apps/reference/docs/guides/functions/auth.mdx @@ -0,0 +1,63 @@ +--- +id: auth +title: Auth +description: Supabase Edge Functions and Auth. +--- + +Edge Functions work seamlessly with [Supabase Auth](/docs/guides/auth), allowing you to identify which user called your function. + +When [invoking](/docs/reference/javascript/invoke) a function with one of the [client libraries](/docs/reference), the logged in user's JWT is automatically attached to the function call and becomes accessible within your function. + +This is important, for example, to identify which customer's credit card should be charged. You can see this concept end-to-end in our [Stripe example app](https://github.com/supabase-community/expo-stripe-payments-with-supabase-functions). + +## Auth Context & RLS + +By creating a supabase client with the auth context from the function, you can do two things: + +1. Get the user object. +2. Run queries in the context of the user with [Row Level Security (RLS)](http://localhost:3010/docs/guides/auth/row-level-security) policies enforced. + +```js title="supabase/functions/select-from-table-with-auth-rls/index.ts" +import { serve } from 'https://deno.land/std@0.131.0/http/server.ts' +import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.0.0-rc.12' + +serve(async (req: Request) => { + try { + // Create a Supabase client with the Auth context of the logged in user. + const supabaseClient = createClient( + // Supabase API URL - env var exported by default. + Deno.env.get('SUPABASE_URL') ?? '', + // Supabase API ANON KEY - env var exported by default. + Deno.env.get('SUPABASE_ANON_KEY') ?? '', + // Create client with Auth context of the user that called the function. + // This way your row-level-security (RLS) policies are applied. + // highlight-next-line + { global: { headers: { Authorization: req.headers.get('Authorization')! } } } + ) + // Now we can get the session or user object + // highlight-start + const { + data: { user }, + } = await supabaseClient.auth.getUser() + // highlight-end + + // And we can run queries in the context of our authenticated user + // highlight-start + const { data, error } = await supabaseClient.from('users').select('*') + if (error) throw error + // highlight-end + + return new Response(JSON.stringify({ user, data }), { + headers: { 'Content-Type': 'application/json' }, + status: 200, + }) + } catch (error) { + return new Response(JSON.stringify({ error: error.message }), { + headers: { 'Content-Type': 'application/json' }, + status: 400, + }) + } +}) +``` + +See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/select-from-table-with-auth-rls/index.ts). diff --git a/apps/reference/docs/guides/functions/examples.mdx b/apps/reference/docs/guides/functions/examples.mdx new file mode 100644 index 00000000000..e56dc4da517 --- /dev/null +++ b/apps/reference/docs/guides/functions/examples.mdx @@ -0,0 +1,47 @@ +--- +id: examples +title: Examples +description: Useful Supabase Edge Functions Examples. +--- + +import ButtonCard from '@site/src/components/ButtonCard' +const examples = [ + { + name: 'With supabase-js', + description: 'Use the Supabase client inside your Edge Function.', + href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/select-from-table-with-auth-rls/index.ts', + }, + { + name: 'With CORS headers', + description: 'Send CORS headers for invoking from the browser.', + href: 'https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts', + }, + { + name: 'React Native with Stripe', + description: 'Full example for using Supabase and Stripe, with Expo.', + href: 'https://github.com/supabase-community/expo-stripe-payments-with-supabase-functions', + }, + { + name: 'Flutter with Stripe', + description: 'Full example for using Supabase and Stripe, with Flutter.', + href: 'https://github.com/supabase-community/flutter-stripe-payments-with-supabase-functions', + }, +] + +You can find a list of useful [Edge Function Examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) in our GitHub repository. + +
+
+ {examples.map((x) => ( +
+ +
+ ))} +
+
diff --git a/apps/reference/nav/_referenceSidebars.js b/apps/reference/nav/_referenceSidebars.js index 9871aa55528..e0150208708 100644 --- a/apps/reference/nav/_referenceSidebars.js +++ b/apps/reference/nav/_referenceSidebars.js @@ -156,7 +156,12 @@ const sidebars = { type: 'category', label: 'Edge Functions', collapsed: true, - items: ['guides/functions', 'guides/functions/cicd-workflow'], + items: [ + 'guides/functions', + 'guides/functions/auth', + 'guides/functions/examples', + 'guides/functions/cicd-workflow', + ], }, { type: 'category', diff --git a/examples/edge-functions/supabase/functions/get-tshirt-competition/README.md b/examples/edge-functions/supabase/functions/get-tshirt-competition/README.md index 9f6033295a7..8d0bcb0dd72 100644 --- a/examples/edge-functions/supabase/functions/get-tshirt-competition/README.md +++ b/examples/edge-functions/supabase/functions/get-tshirt-competition/README.md @@ -2,10 +2,10 @@ To celebrate the support of GET requests in Supabase Edge Functions we're giving away some limited edition Functions Shirts! -To win a Supabase Edge Functions T-Shirt, make a GET request to https://obuldanrptloktxcffvn.functions.supabase.co/get-tshirt-competition with your email address, your Twitter handle (optional), and the correct answer, e.g. +To win a Supabase Edge Functions T-Shirt, make a GET request to https://obuldanrptloktxcffvn.functions.supabase.co/get-tshirt-competition with your email address, your Twitter handle (optional), your t-shirt size (S-2XL) and the correct answer, e.g. ```text -https://obuldanrptloktxcffvn.functions.supabase.co/get-tshirt-competition?email=testr@test.de&twitter=thorwebdev&answer=20 +https://obuldanrptloktxcffvn.functions.supabase.co/get-tshirt-competition?email=testr@test.de&twitter=thorwebdev&size=2XL&answer=20 ``` You can read the functions source code to figure out the answer ;) diff --git a/examples/edge-functions/supabase/functions/get-tshirt-competition/index.ts b/examples/edge-functions/supabase/functions/get-tshirt-competition/index.ts index 75f0985258d..392da9f29f0 100644 --- a/examples/edge-functions/supabase/functions/get-tshirt-competition/index.ts +++ b/examples/edge-functions/supabase/functions/get-tshirt-competition/index.ts @@ -27,11 +27,17 @@ serve(async (req) => { const url = new URL(req.url) const email = url.searchParams.get('email') const twitter = url.searchParams.get('twitter') + const size = url.searchParams.get('size') const answer = url.searchParams.get('answer') - if (!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email ?? '') || !answer) + if ( + !/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email ?? '') || + !answer || + !twitter || + !size + ) throw new Error( - `You're missing either a valid 'email' and/or 'answer' param(s). HINT: https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/get-tshirt-competition/index.ts` + `Please provide valid 'email', 'twitter', 'size', and 'answer' params. HINT: https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/get-tshirt-competition/index.ts` ) if (Number(answer) !== positionInAlphabet(email!)) @@ -50,6 +56,7 @@ serve(async (req) => { { email, twitter, + size, }, { onConflict: 'email' } ) @@ -71,4 +78,4 @@ serve(async (req) => { }) // To invoke: -// curl -i --location --request GET 'http://localhost:54321/functions/v1/get-tshirt-competition?email=testr@test.de&answer=20' +// curl -i --location --request GET 'http://localhost:54321/functions/v1/get-tshirt-competition?email=testr@test.de&twitter=thorwebdev&size=2XL&answer=20'