Pages Router
Pages Router
Auth
Next.js comes in two flavors: the App Router and the Pages Router. You can set up Server-Side
Auth with either strategy. You can even use both in the same application.
Project URL
https://ioauubebagztwzpefnjm.supabase.co
Anon key
.env.local
1 NEXT_PUBLIC_SUPABASE_URL=<your_supabase_project_url>
2 NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
To access Supabase from your Next.js app, you need 4 types of Supabase clients:
Create a utils/supabase folder with a file for each type of client. Then copy the utility
functions for each client type.
Since Supabase is being called from a component, use the client defined in
@/utils/supabase/component.ts .
pages/login.tsx
1 import { useRouter } from 'next/router'
2 import { useState } from 'react'
3
4 import { createClient } from '@/utils/supabase/component'
5
6 export default function LoginPage() {
7 const router = useRouter()
8 const supabase = createClient()
9
10 const [email, setEmail] = useState('')
11 const [password, setPassword] = useState('')
12
13 async function logIn() {
14 const { error } = await supabase.auth.signInWithPassword({ email, password
15 if (error) {
16 console.error(error)
17 }
18 router.push('/')
19 }
20
21 async function signUp() {
22 const { error } = await supabase.auth.signUp({ email, password })
23 if (error) {
24 console.error(error)
25 }
26 router.push('/')
27 }
28
29 return (
30 <main>
31 <form>
32 <label htmlFor="email">Email:</label>
33 <input id="email" type="email" value={email} onChange={(e) => setEmail(
34 <label htmlFor="password">Password:</label>
35 <input
36 id="password"
37 type="password"
38 value={password}
39 onChange={(e) => setPassword(e.target.value)}
40 />
41 <button type="button" onClick={logIn}>
42 Log in
43 </button>
44 <button type="button" onClick={signUp}>
45 Sign up
46 </button>
47 </form>
48 </main>
49 )
50 }
If you have email confirmation turned on (the default), a new user will receive an email
confirmation after signing up.
Go to the Auth templates page in your dashboard. In the Confirm signup template,
change {{ .ConfirmationURL }} to {{ .SiteURL }}/api/auth/confirm?token_hash=
{{ .TokenHash }}&type=signup .
Create an API route for api/auth/confirm . When a user clicks their confirmation email
link, exchange their secure code for an Auth token.
Since this is an API route, use the Supabase client from @/utils/supabase/api.ts .
pages/api/auth/confirm.ts pages/error.tsx
1 import { type EmailOtpType } from '@supabase/supabase-js'
2 import type { NextApiRequest, NextApiResponse } from 'next'
3
4 import createClient from '@/utils/supabase/api'
5
6 function stringOrFirstString(item: string | string[] | undefined) {
7 return Array.isArray(item) ? item[0] : item
8 }
9
10 export default async function handler(req: NextApiRequest, res: NextApiResponse
11 if (req.method !== 'GET') {
12 res.status(405).appendHeader('Allow', 'GET').end()
13 return
14 }
15
16 const queryParams = req.query
17 const token_hash = stringOrFirstString(queryParams.token_hash)
18 const type = stringOrFirstString(queryParams.type)
19
20 let next = '/error'
21
22 if (token_hash && type) {
23 const supabase = createClient(req, res)
24 const { error } = await supabase.auth.verifyOtp({
25 type: type as EmailOtpType,
26 token_hash,
27 })
28 if (error) {
29 console.error(error)
30 } else {
31 next = stringOrFirstString(queryParams.next) || '/'
32 }
33 }
34
35 res.redirect(next)
36 }
If you use dynamic server-side rendering, you can serve a page to authenticated users only
by checking for the user data in getServerSideProps . Unauthenticated users will be
redirected to the home page.
Since you're calling Supabase from getServerSideProps , use the client from
@/utils/supabase/server-props.ts .
Be careful when protecting pages. The server gets the user session from the cookies, which
can be spoofed by anyone.
Always use supabase.auth.getUser() to protect pages and user data.
Never trust supabase.auth.getSession() inside server code. It isn't guaranteed to
revalidate the Auth token.
It's safe to trust getUser() because it sends a request to the Supabase Auth server every
time to revalidate the Auth token.
pages/private.tsx
1 import type { User } from '@supabase/supabase-js'
2 import type { GetServerSidePropsContext } from 'next'
3
4 import { createClient } from '@/utils/supabase/server-props'
5
6 export default function PrivatePage({ user }: { user: User }) {
7 return <h1>Hello, {user.email || 'user'}!</h1>
8 }
9
10 export async function getServerSideProps(context: GetServerSidePropsContext) {
11 const supabase = createClient(context)
12
13 const { data, error } = await supabase.auth.getUser()
14
15 if (error || !data) {
16 return {
17 redirect: {
18 destination: '/',
19 permanent: false,
20 },
21 }
22 }
23
24 return {
25 props: {
26 user: data.user,
27 },
28 }
29 }
8 Fetch static data using `getStaticProps`
You can also fetch static data at build time using Supabase. Note that there's no session or
user at build time, so the data will be the same for everyone who sees the page.
Add some countries data to your database by running the Countries Quickstart in the
dashboard.
Then fetch the countries data using getStaticProps with the client from
@/utils/supabase/static-props.ts .
pages/public.tsx
1 import { createClient } from '@/utils/supabase/static-props'
2
3 export default function PublicPage({ data }: { data?: any[] }) {
4 return <pre>{data && JSON.stringify(data, null, 2)}</pre>
5 }
6
7 export async function getStaticProps() {
8 const supabase = createClient()
9
10 const { data, error } = await supabase.from('countries').select()
11
12 if (error || !data) {
13 return { props: {} }
14 }
15
16 return { props: { data } }
17 }
Congratulations
You can now use any Supabase features from your client or server code!
© Supabase Inc
Contributing
Author Styleguide
Open Source
SupaSquad
Privacy Settings