Skip to content

Commit

Permalink
chore: merge upstream updates
Browse files Browse the repository at this point in the history
  • Loading branch information
jingsam committed Aug 24, 2024
2 parents 23eac0a + e77f8b9 commit 6dc5a82
Show file tree
Hide file tree
Showing 58 changed files with 1,447 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,10 @@ export const functions: NavMenuConstant = {
name: 'Examples',
url: undefined,
items: [
{
name: 'Auth Send Email Hook',
url: '/guides/functions/examples/auth-send-email-hook-react-email-resend',
},
{
name: 'CORS support for invoking from the browser',
url: '/guides/functions/cors',
Expand Down Expand Up @@ -1295,6 +1299,10 @@ export const functions: NavMenuConstant = {
url: '/guides/functions/examples/sentry-monitoring',
},
{ name: 'OpenAI API', url: '/guides/ai/examples/openai' },
{
name: 'React Email',
url: '/guides/functions/examples/auth-send-email-hook-react-email-resend',
},
{
name: 'Sending Emails with Resend',
url: '/guides/functions/examples/send-emails',
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/guides/api/api-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ select
using (true);
```

And similarity for disallowing access:
And similarly for disallowing access:

```sql
create policy "Disallow public access" on profiles to anon for
Expand Down
18 changes: 15 additions & 3 deletions apps/docs/content/guides/auth/auth-hooks/send-email-hook.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,9 @@ select
defaultActiveId="http-send-email-with-resend"
>
<TabPanel id="http-send-email-with-resend" label="Use Resend as an email provider">
You can configure [Resend](https://resend.com/) as the custom email provider through the "Send Email" hook. This allows you to take advantage of Resend's developer-friendly APIs to send emails and leverage [React Email](https://react.email/) for managing your email templates. If you want to send emails through the Supabase Resend integration, which uses Resend's SMTP server, check out [this integration](/partners/integrations/resend) instead.
You can configure [Resend](https://resend.com/) as the custom email provider through the "Send Email" hook. This allows you to take advantage of Resend's developer-friendly APIs to send emails and leverage [React Email](https://react.email/) for managing your email templates. For a more advanced React Email tutorial, refer to [this guide](/docs/guides/functions/examples/auth-send-email-hook-react-email-resend).

If you want to send emails through the Supabase Resend integration, which uses Resend's SMTP server, check out [this integration](/partners/integrations/resend) instead.

Create a `.env` file with the following environment variables:

Expand All @@ -462,16 +464,22 @@ RESEND_API_KEY=your_resend_api_key
SEND_EMAIL_HOOK_SECRET=<base64_secret>
```

<Admonition type="info">

You can generate the secret in the [Auth Hooks](/dashboard/project/_/auth/hooks) section of the Supabase dashboard. Make sure to remove the `v1,whsec_` prefix!

</Admonition>

Set the secrets in your Supabase project:

```bash
$ supabase secret set --env-file .env
supabase secrets set --env-file .env
```

Create a new edge function:

```bash
$ supabase functions new send-email
supabase functions new send-email
```

Add the following code to your edge function:
Expand All @@ -484,6 +492,10 @@ const resend = new Resend(Deno.env.get("RESEND_API_KEY") as string);
const hookSecret = Deno.env.get("SEND_EMAIL_HOOK_SECRET") as string;

Deno.serve(async (req) => {
if (req.method !== "POST") {
return new Response("not allowed", { status: 400 });
}

const payload = await req.text();
const headers = Object.fromEntries(req.headers);
const wh = new Webhook(hookSecret);
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/guides/auth/jwts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ The first segment `eyJhbGciOiJIUzI1NiJ9` is known as the "header", and when deco
}
```

The second segment `eyJzdWIiOiIwMDAxIiwibmFtZSI6IlNhbSBWaW1lcyIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE4MjM5MDIyfQ` contains our original payload:
The second segment <code className="break-all">eyJzdWIiOiIwMDAxIiwibmFtZSI6IlNhbSBWaW1lcyIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE4MjM5MDIyfQ</code> contains our original payload:

```js
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
---
title: 'Custom Auth Emails with React Email and Resend'
description: 'Use the send email hook to send custom auth emails with React Email and Resend in Supabase Edge Functions.'
tocVideo: 'tlA7BomSCgU'
---

Use the [send email hook](/docs/guides/auth/auth-hooks/send-email-hook?queryGroups=language&language=http) to send custom auth emails with [React Email](https://react.email/) and [Resend](https://resend.com/) in Supabase Edge Functions.

<Admonition type="info">

Prefer to jump straight to the code? [Check out the example on GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/auth-hook-react-email-resend).

</Admonition>

### Prerequisites

To get the most out of this guide, you’ll need to:

- [Create a Resend API key](https://resend.com/api-keys)
- [Verify your domain](https://resend.com/domains)

Make sure you have the latest version of the [Supabase CLI](https://supabase.com/docs/guides/cli#installation) installed.

### 1. Create Supabase function

Create a new function locally:

```bash
supabase functions new send-email
```

### 2. Edit the handler function

Paste the following code into the `index.ts` file:

```tsx supabase/functions/send-email/index.ts
import React from 'npm:[email protected]'
import { Webhook } from 'https://esm.sh/[email protected]'
import { Resend } from 'npm:[email protected]'
import { renderAsync } from 'npm:@react-email/[email protected]'
import { MagicLinkEmail } from './_templates/magic-link.tsx'

const resend = new Resend(Deno.env.get('RESEND_API_KEY') as string)
const hookSecret = Deno.env.get('SEND_EMAIL_HOOK_SECRET') as string

Deno.serve(async (req) => {
if (req.method !== 'POST') {
return new Response('not allowed', { status: 400 })
}

const payload = await req.text()
const headers = Object.fromEntries(req.headers)
const wh = new Webhook(hookSecret)
try {
const {
user,
email_data: { token, token_hash, redirect_to, email_action_type },
} = wh.verify(payload, headers) as {
user: {
email: string
}
email_data: {
token: string
token_hash: string
redirect_to: string
email_action_type: string
site_url: string
token_new: string
token_hash_new: string
}
}

const html = await renderAsync(
React.createElement(MagicLinkEmail, {
supabase_url: Deno.env.get('SUPABASE_URL') ?? '',
token,
token_hash,
redirect_to,
email_action_type,
})
)

const { error } = await resend.emails.send({
from: 'welcome <[email protected]>',
to: [user.email],
subject: 'Supa Custom MagicLink!',
html,
})
if (error) {
throw error
}
} catch (error) {
console.log(error)
return new Response(
JSON.stringify({
error: {
http_code: error.code,
message: error.message,
},
}),
{
status: 401,
headers: { 'Content-Type': 'application/json' },
}
)
}

const responseHeaders = new Headers()
responseHeaders.set('Content-Type', 'application/json')
return new Response(JSON.stringify({}), {
status: 200,
headers: responseHeaders,
})
})
```

### 3. Create React Email Templates

Create a new folder `_templates` and create a new file `magic-link.tsx` with the following code:

```tsx supabase/functions/send-email/_templates/magic-link.tsx
import {
Body,
Container,
Head,
Heading,
Html,
Link,
Preview,
Text,
} from 'npm:@react-email/[email protected]'
import * as React from 'npm:[email protected]'

interface MagicLinkEmailProps {
supabase_url: string
email_action_type: string
redirect_to: string
token_hash: string
token: string
}

export const MagicLinkEmail = ({
token,
supabase_url,
email_action_type,
redirect_to,
token_hash,
}: MagicLinkEmailProps) => (
<Html>
<Head />
<Preview>Log in with this magic link</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>Login</Heading>
<Link
href={`${supabase_url}/auth/v1/verify?token=${token_hash}&type=${email_action_type}&redirect_to=${redirect_to}`}
target="_blank"
style={{
...link,
display: 'block',
marginBottom: '16px',
}}
>
Click here to log in with this magic link
</Link>
<Text style={{ ...text, marginBottom: '14px' }}>
Or, copy and paste this temporary login code:
</Text>
<code style={code}>{token}</code>
<Text
style={{
...text,
color: '#ababab',
marginTop: '14px',
marginBottom: '16px',
}}
>
If you didn&apos;t try to login, you can safely ignore this email.
</Text>
<Text style={footer}>
<Link
href="https://demo.vercel.store/"
target="_blank"
style={{ ...link, color: '#898989' }}
>
ACME Corp
</Link>
, the famouse demo corp.
</Text>
</Container>
</Body>
</Html>
)

export default MagicLinkEmail

const main = {
backgroundColor: '#ffffff',
}

const container = {
paddingLeft: '12px',
paddingRight: '12px',
margin: '0 auto',
}

const h1 = {
color: '#333',
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
fontSize: '24px',
fontWeight: 'bold',
margin: '40px 0',
padding: '0',
}

const link = {
color: '#2754C5',
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
fontSize: '14px',
textDecoration: 'underline',
}

const text = {
color: '#333',
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
fontSize: '14px',
margin: '24px 0',
}

const footer = {
color: '#898989',
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
fontSize: '12px',
lineHeight: '22px',
marginTop: '12px',
marginBottom: '24px',
}

const code = {
display: 'inline-block',
padding: '16px 4.5%',
width: '90.5%',
backgroundColor: '#f4f4f4',
borderRadius: '5px',
border: '1px solid #eee',
color: '#333',
}
```

<Admonition type="info">

You can find a selection of React Email templates in the [React Email Eamples](https://react.email/examples).

</Admonition>

### 4. Deploy the Function

Deploy function to Supabase:

```bash
supabase functions deploy send-email --no-verify-jwt
```

Note down the function URL, you will need it in the next step!

### 5. Configure the Send Email Hook

- Go to the [Auth Hooks](/dashboard/project/_/auth/hooks) section of the Supabase dashboard and create a new "Send Email hook".
- Select HTTPS as the hook type.
- Paste the function URL in the "URL" field.
- Click "Generate Secret" to generate your webhook secret and note it down.
- Click "Create" to save the hook configuration.

Store these secrets in your `.env` file.

```bash supabase/functions/.env
RESEND_API_KEY=your_resend_api_key
SEND_EMAIL_HOOK_SECRET=<base64_secret>
```

<Admonition type="info">

You can generate the secret in the [Auth Hooks](/dashboard/project/_/auth/hooks) section of the Supabase dashboard. Make sure to remove the `v1,whsec_` prefix!

</Admonition>

Set the secrets from the `.env` file:

```bash
supabase secrets set --env-file supabase/functions/.env
```

That's it, now your Supabase Edge Function will be triggered anytime an Auth Email needs to be send to the user!

## More Resources

- [Send Email Hooks](/docs/guides/auth/auth-hooks/send-email-hook)
- [Auth Hooks](/docs/guides/auth/auth-hooks)
3 changes: 3 additions & 0 deletions apps/docs/content/guides/platform/going-into-prod.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ After developing your project and deciding it's Production Ready, you should run
- You can set up your own backup systems using tools like [pg_dump](https://www.postgresqltutorial.com/postgresql-backup-database/) or [wal-g](https://github.com/wal-g/wal-g).
- Nightly backups for Pro Plan projects are available on the Supabase dashboard for up to 7 days.
- Point in Time Recovery (PITR) allows a project to be backed up at much shorter intervals. This provides users an option to restore to any chosen point of up to seconds in granularity. In terms of Recovery Point Objective (RPO), Daily Backups would be suitable for projects willing to lose up to 24 hours worth of data. If a lower RPO is required, enable PITR.
- Supabase Projects use disks that offer 99.8-99.9% durability by default.
- Use Read Replicas if you require availability resilience to a disk failure event
- Use PITR if you require durability resilience to a disk failure event
- Upgrading to the Supabase Pro Plan will give you [access to our support team](https://supabase.com/dashboard/support/new).

## Rate limiting, resource allocation, & abuse prevention
Expand Down
Loading

0 comments on commit 6dc5a82

Please sign in to comment.