forked from supabase/supabase
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'supabase:master' into master
- Loading branch information
Showing
32 changed files
with
836 additions
and
417 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
258 changes: 258 additions & 0 deletions
258
.../docs/pages/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
import Layout from '~/layouts/DefaultGuideLayout' | ||
|
||
export const meta = { | ||
title: 'Email Auth with PKCE flow for SSR', | ||
description: | ||
'Learn how to configure email authentication in your server-side rendering (SSR) application to work with the PKCE flow.', | ||
subtitle: | ||
'Learn how to configure email authentication in your server-side rendering (SSR) application to work with the PKCE flow.', | ||
} | ||
|
||
### Install Supabase Auth Helpers | ||
|
||
The Auth Helpers will assist you in implementing user authentication within your server-side rendering (SSR) framework. | ||
|
||
<Tabs scrollable size="small" type="underlined" defaultActiveId="nextjs"> | ||
|
||
<TabPanel id="nextjs" label="NextJS"> | ||
|
||
```bash | ||
npm install @supabase/auth-helpers-nextjs @supabase/supabase-js | ||
``` | ||
|
||
</TabPanel> | ||
|
||
<TabPanel id="sveltekit" label="SvelteKit"> | ||
|
||
```bash | ||
npm install @supabase/auth-helpers-sveltekit @supabase/supabase-js | ||
``` | ||
|
||
</TabPanel> | ||
|
||
</Tabs> | ||
|
||
### Set environment variables | ||
|
||
Create an `.env.local` file in your project root directory. You can get your `SITE_URL` and `ANON_KEY` from inside of the [dashboard](https://supabase.com/dashboard/project/_/settings/api). | ||
|
||
<Tabs scrollable size="small" type="underlined" defaultActiveId="nextjs"> | ||
|
||
<TabPanel id="nextjs" label="NextJS"> | ||
|
||
```bash .env.local | ||
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url | ||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key | ||
``` | ||
|
||
</TabPanel> | ||
<TabPanel id="sveltekit" label="SvelteKit"> | ||
|
||
```bash .env.local | ||
PUBLIC_SUPABASE_URL=your_supabase_project_url | ||
PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key | ||
``` | ||
|
||
</TabPanel> | ||
</Tabs> | ||
|
||
### Setting up the Auth Helpers | ||
|
||
When using the Supabase client on the server, you must perform extra steps to ensure the user's auth session remains active. Since the user's session is tracked in a cookie, we need to read this cookie and update it if necessary. | ||
|
||
<Tabs | ||
scrollable | ||
size="small" | ||
type="underlined" | ||
defaultActiveId="nextjs" | ||
> | ||
<TabPanel id="nextjs" label="NextJS"> | ||
Next.js Server Components allow you to read a cookie but not write back to it. Middleware on the other hand allow you to both read and write to cookies. | ||
|
||
Next.js [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) runs immediately before each route is rendered. We'll use Middleware to refresh the user's session before loading Server Component routes. | ||
|
||
Create a new `middleware.js` file in the root of your project and populate with the following: | ||
|
||
```js middleware.js | ||
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' | ||
import { NextResponse } from 'next/server' | ||
|
||
export async function middleware(req) { | ||
const res = NextResponse.next() | ||
const supabase = createMiddlewareClient({ req, res }) | ||
await supabase.auth.getSession() | ||
return res | ||
} | ||
``` | ||
|
||
</TabPanel> | ||
<TabPanel id="sveltekit" label="SvelteKit"> | ||
Create a new `hooks.server.js` file in the root of your project and populate with the following: | ||
|
||
```ts src/hooks.server.js | ||
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public' | ||
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit' | ||
import type { Handle } from '@sveltejs/kit' | ||
|
||
export const handle: Handle = async ({ event, resolve }) => { | ||
event.locals.supabase = createSupabaseServerClient({ | ||
supabaseUrl: PUBLIC_SUPABASE_URL, | ||
supabaseKey: PUBLIC_SUPABASE_ANON_KEY, | ||
event, | ||
}) | ||
|
||
event.locals.getSession = async () => { | ||
const { | ||
data: { session }, | ||
} = await event.locals.supabase.auth.getSession() | ||
return session | ||
} | ||
|
||
return resolve(event, { | ||
filterSerializedResponseHeaders(name) { | ||
return name === 'content-range' | ||
}, | ||
}) | ||
} | ||
``` | ||
|
||
</TabPanel> | ||
</Tabs> | ||
|
||
### Create API endpoint for handling `token_hash` | ||
|
||
In order to use the updated email links we will need to setup a endpoint for verifying the `token_hash` along with the `type` to exchange `token_hash` for the user's `session`, which is set as a cookie for future requests made to Supabase. | ||
|
||
<Tabs | ||
scrollable | ||
size="small" | ||
type="underlined" | ||
defaultActiveId="nextjs" | ||
> | ||
<TabPanel id="nextjs" label="NextJS"> | ||
Create a new file at `app/auth/confirm/route.js` and populate with the following: | ||
|
||
```js app/auth/confirm/route.js | ||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' | ||
import { cookies } from 'next/headers' | ||
import { NextResponse } from 'next/server' | ||
|
||
export async function GET(req) { | ||
const { searchParams } = new URL(req.url) | ||
const token_hash = searchParams.get('token_hash') | ||
const type = searchParams.get('type') | ||
const next = searchParams.get('next') ?? '/' | ||
|
||
if (token_hash && type) { | ||
const supabase = createRouteHandlerClient({ cookies }) | ||
const { error } = await supabase.auth.verifyOtp({ type, token_hash }) | ||
if (!error) { | ||
return NextResponse.redirect(new URL(`/${next.slice(1)}`, req.url)) | ||
} | ||
} | ||
|
||
// return the user to an error page with some instructions | ||
return NextResponse.redirect(new URL('/auth/auth-code-error', req.url)) | ||
} | ||
``` | ||
</TabPanel> | ||
<TabPanel id="sveltekit" label="SvelteKit"> | ||
Create a new file at `src/routes/auth/confirm/+server.js` and populate with the following: | ||
```js src/routes/auth/confirm/+server.js | ||
import { redirect } from '@sveltejs/kit'; | ||
|
||
export const GET = async (event) => { | ||
const { | ||
url, | ||
locals: { supabase } | ||
} = event; | ||
const token_hash = url.searchParams.get('token') as string; | ||
const type = url.searchParams.get('type') as string; | ||
const next = url.searchParams.get('next') ?? '/'; | ||
|
||
if (token_hash && type) { | ||
const { error } = await supabase.auth.verifyOtp({ token_hash, type }); | ||
if (!error) { | ||
throw redirect(303, `/${next.slice(1)}`); | ||
} | ||
} | ||
|
||
// return the user to an error page with some instructions | ||
throw redirect(303, '/auth/auth-code-error'); | ||
}; | ||
``` | ||
</TabPanel> | ||
</Tabs> | ||
### Update email templates with URL for API endpoint | ||
Let's update the URL in our email templates to point to our new confirmation endpoint for the user to get confirmed. | ||
**Confirm signup template** | ||
```html | ||
<h2>Confirm your signup</h2> | ||
|
||
<p>Follow this link to confirm your user:</p> | ||
<p> | ||
<a href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email" | ||
>Confirm your email</a | ||
> | ||
</p> | ||
``` | ||
**Invite user template** | ||
```html | ||
<h2>You have been invited</h2> | ||
|
||
<p> | ||
You have been invited to create a user on {{ .SiteURL }}. Follow this link to accept the invite: | ||
</p> | ||
|
||
<p> | ||
<a | ||
href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=invite&next=/path-to-your-update-password-page" | ||
>Accept the invite</a | ||
> | ||
</p> | ||
``` | ||
**Magic Link template** | ||
```html | ||
<h2>Magic Link</h2> | ||
|
||
<p>Follow this link to login:</p> | ||
<p><a href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Log In</a></p> | ||
``` | ||
**Change Email Address template** | ||
```html | ||
<h2>Confirm Change of Email</h2> | ||
|
||
<p>Follow this link to confirm the update of your email from {{ .Email }} to {{ .NewEmail }}:</p> | ||
<p><a href="{{ .ConfirmationURL }}">Change Email</a></p> | ||
``` | ||
**Reset Password template** | ||
```html | ||
<h2>Reset Password</h2> | ||
|
||
<p>Follow this link to reset the password for your user:</p> | ||
<p> | ||
<a | ||
href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=recovery&next=/path-to-your-update-password-page" | ||
>Reset Password</a | ||
> | ||
</p> | ||
``` | ||
export const Page = ({ children }) => <Layout meta={meta} children={children} /> | ||
export default Page |
Oops, something went wrong.