mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 23:29:08 +03:00
Merge pull request #5464 from supabase/example/update-nextjs-with-auth
feat: update nextjs auth example
This commit is contained in:
10 files changed
+2868
-2585
No files matched your search
+891
-773
File diff suppressed because it is too large.
Load diff
@@ -7,9 +7,8 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^1.11.9",
|
||||
"@supabase/ui": "^0.24.2",
|
||||
"next": "11.1.1",
|
||||
"@supabase/supabase-auth-helpers": "^1.0.6",
|
||||
"next": "^11.1.4",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"swr": "^0.5.5"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Auth } from '@supabase/ui'
|
||||
import { supabase } from '../utils/initSupabase'
|
||||
import { UserProvider } from '@supabase/supabase-auth-helpers/react'
|
||||
import { supabaseClient } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
import './../style.css'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<main className={'dark'}>
|
||||
<Auth.UserContextProvider supabaseClient={supabase}>
|
||||
<UserProvider supabaseClient={supabaseClient}>
|
||||
<Component {...pageProps} />
|
||||
</Auth.UserContextProvider>
|
||||
</UserProvider>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* NOTE: this file is only needed if you're doing SSR (getServerSideProps)!
|
||||
*/
|
||||
import { supabase } from '../../utils/initSupabase'
|
||||
|
||||
export default function handler(req, res) {
|
||||
supabase.auth.api.setAuthCookie(req, res)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { handleAuth } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
|
||||
export default handleAuth()
|
||||
@@ -1,13 +0,0 @@
|
||||
import { supabase } from '../../utils/initSupabase'
|
||||
|
||||
// Example of how to verify and get user data server-side.
|
||||
const getUser = async (req, res) => {
|
||||
const token = req.headers.token
|
||||
|
||||
const { data: user, error } = await supabase.auth.api.getUser(token)
|
||||
|
||||
if (error) return res.status(401).json({ error: error.message })
|
||||
return res.status(200).json(user)
|
||||
}
|
||||
|
||||
export default getUser
|
||||
@@ -1,106 +1,43 @@
|
||||
import Link from 'next/link'
|
||||
import useSWR from 'swr'
|
||||
import { Auth, Card, Typography, Space, Button, Icon } from '@supabase/ui'
|
||||
import { supabase } from '../utils/initSupabase'
|
||||
import { useUser, Auth } from '@supabase/supabase-auth-helpers/react'
|
||||
import { supabaseClient } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const fetcher = (url, token) =>
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: new Headers({ 'Content-Type': 'application/json', token }),
|
||||
credentials: 'same-origin',
|
||||
}).then((res) => res.json())
|
||||
|
||||
const Index = () => {
|
||||
const { user, session } = Auth.useUser()
|
||||
const { data, error } = useSWR(session ? ['/api/getUser', session.access_token] : null, fetcher)
|
||||
const [authView, setAuthView] = useState('sign_in')
|
||||
const LoginPage = () => {
|
||||
const { user, error } = useUser()
|
||||
const [data, setData] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event === 'PASSWORD_RECOVERY') setAuthView('forgotten_password')
|
||||
if (event === 'USER_UPDATED') setTimeout(() => setAuthView('sign_in'), 1000)
|
||||
// Send session to /api/auth route to set the auth cookie.
|
||||
// NOTE: this is only needed if you're doing SSR (getServerSideProps)!
|
||||
fetch('/api/auth', {
|
||||
method: 'POST',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ event, session }),
|
||||
}).then((res) => res.json())
|
||||
})
|
||||
|
||||
return () => {
|
||||
authListener.unsubscribe()
|
||||
async function loadData() {
|
||||
const { data } = await supabaseClient.from('test').select('*')
|
||||
setData(data)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const View = () => {
|
||||
if (!user)
|
||||
return (
|
||||
<Space direction="vertical" size={8}>
|
||||
<div>
|
||||
<img src="https://app.supabase.io/img/supabase-dark.svg" width="96" />
|
||||
<Typography.Title level={3}>Welcome to Supabase Auth</Typography.Title>
|
||||
</div>
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
providers={['google', 'github']}
|
||||
view={authView}
|
||||
socialLayout="horizontal"
|
||||
socialButtonSize="xlarge"
|
||||
/>
|
||||
</Space>
|
||||
)
|
||||
// Only run query once user is logged in.
|
||||
if (user) loadData()
|
||||
}, [user])
|
||||
|
||||
if (!user)
|
||||
return (
|
||||
<Space direction="vertical" size={6}>
|
||||
{authView === 'forgotten_password' && <Auth.UpdatePassword supabaseClient={supabase} />}
|
||||
{user && (
|
||||
<>
|
||||
<Typography.Text>You're signed in</Typography.Text>
|
||||
<Typography.Text strong>Email: {user.email}</Typography.Text>
|
||||
|
||||
<Button
|
||||
icon={<Icon type="LogOut" />}
|
||||
type="outline"
|
||||
onClick={() => supabase.auth.signOut()}
|
||||
>
|
||||
Log out
|
||||
</Button>
|
||||
{error && <Typography.Text type="danger">Failed to fetch user!</Typography.Text>}
|
||||
{data && !error ? (
|
||||
<>
|
||||
<Typography.Text type="success">
|
||||
User data retrieved server-side (in API route):
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</Typography.Text>
|
||||
</>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
|
||||
<Typography.Text>
|
||||
<Link href="/profile">
|
||||
<a>SSR example with getServerSideProps</a>
|
||||
</Link>
|
||||
</Typography.Text>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
<>
|
||||
{error && <p>{error.message}</p>}
|
||||
<Auth
|
||||
// view="update_password"
|
||||
supabaseClient={supabaseClient}
|
||||
providers={['google', 'github']}
|
||||
socialLayout="horizontal"
|
||||
socialButtonSize="xlarge"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: '420px', margin: '96px auto' }}>
|
||||
<Card>
|
||||
<View />
|
||||
</Card>
|
||||
</div>
|
||||
<>
|
||||
<button onClick={() => supabaseClient.auth.signOut()}>Sign out</button>
|
||||
<p>user:</p>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
<p>client-side data fetching with RLS</p>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Index
|
||||
export default LoginPage
|
||||
@@ -1,41 +1,13 @@
|
||||
import Link from 'next/link'
|
||||
import { Card, Typography, Space } from '@supabase/ui'
|
||||
import { supabase } from '../utils/initSupabase'
|
||||
// pages/profile.js
|
||||
import { withAuthRequired } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
|
||||
export default function Profile({ user }) {
|
||||
return (
|
||||
<div style={{ maxWidth: '420px', margin: '96px auto' }}>
|
||||
<Card>
|
||||
<Space direction="vertical" size={6}>
|
||||
<Typography.Text>You're signed in</Typography.Text>
|
||||
<Typography.Text strong>Email: {user.email}</Typography.Text>
|
||||
<Typography.Text type="success">
|
||||
User data retrieved server-side (from Cookie in getServerSideProps):
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text>
|
||||
<Link href="/">
|
||||
<a>Static example with useSWR</a>
|
||||
</Link>
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
<>
|
||||
<div>Hello {user.email}</div>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerSideProps({ req }) {
|
||||
const { user } = await supabase.auth.api.getUserByCookie(req)
|
||||
|
||||
if (!user) {
|
||||
// If no user, redirect to index.
|
||||
return { props: {}, redirect: { destination: '/', permanent: false } }
|
||||
}
|
||||
|
||||
// If there is a user, return it.
|
||||
return { props: { user } }
|
||||
}
|
||||
export const getServerSideProps = withAuthRequired()
|
||||
@@ -1,6 +0,0 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
export const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
)
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user