DOCS Search
Auth
Auth Server-Side Rendering Next.js guide
Setting up Server-Side Auth for Next.js
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.
App Router Pages Router Hybrid router strategies
1 Install Supabase packages
Install the @supabase/supabase-js package and the helper @supabase/ssr package.
1 npm install @supabase/supabase-js @supabase/ssr
2 Set up environment variables
Create a .env.local file in your project root directory.
Fill in your NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY :
Project URL
eCow / eCow Ranch Management
https://ioauubebagztwzpefnjm.supabase.co
Anon key
eCow / eCow Ranch Management
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im
.env.local
1 NEXT_PUBLIC_SUPABASE_URL=<your_supabase_project_url>
2 NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
3 Write utility functions to create Supabase clients
To access Supabase from your Next.js app, you need 4 types of Supabase clients:
1 getServerSideProps client - To access Supabase from getServerSideProps .
2 getStaticProps client - To access Supabase from getStaticProps .
3 Component client - To access Supabase from within components.
4 API route client - To access Supabase from API route handlers.
Create a utils/supabase folder with a file for each type of client. Then copy the utility
functions for each client type.
Why do I need so many types of clients?
What does the `cookies` object do?
utils/supabase/server-props.ts utils/supabase/static-… utils/supabase/comp… utils/supabase/…
1 import { type GetServerSidePropsContext } from 'next'
2 import { createServerClient, serializeCookieHeader } from '@supabase/ssr'
3
4 export function createClient({ req, res }: GetServerSidePropsContext) {
5 const supabase = createServerClient(
6 process.env.NEXT_PUBLIC_SUPABASE_URL!,
7 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
8 {
9 cookies: {
10 getAll() {
11 return Object.keys(req.cookies).map((name) => ({ name, value: req.coo
12 },
13 setAll(cookiesToSet) {
14 res.setHeader(
15 'Set-Cookie',
16 cookiesToSet.map(({ name, value, options }) =>
17 serializeCookieHeader(name, value, options)
18 )
19 )
20 },
21 },
22 }
23 )
24
25 return supabase
26 }
4 Create a login page
Create a login page for your app.
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 }
5 Change the Auth confirmation path
If you have email confirmation turned on (the default), a new user will receive an email
confirmation after signing up.
Change the email template to support a server-side authentication flow.
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 .
6 Create a route handler for Auth confirmation
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 }
7 Make an authenticated-only page using `getServerSideProps`
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're done! To recap, you've successfully:
Called Supabase from a component
Called Supabase from an API route
Called Supabase from getServerSideProps
Called Supabase from getStaticProps
You can now use any Supabase features from your client or server code!
Edit this page on GitHub
Need some help? Contact support
Latest product updates? See Changelog
Something's not right? Check system status
© Supabase Inc
Contributing
Author Styleguide
Open Source
SupaSquad
Privacy Settings