Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update auth0 example with getServerSideProps #11051

Merged
merged 22 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
54dd562
example improved
alfrejivi Mar 13, 2020
2b96b2c
put user cache back
alfrejivi Mar 13, 2020
3512c41
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 13, 2020
018181e
.env.template is back
alfrejivi Mar 13, 2020
071d351
Merge branch 'enhancement/auth0-example' of https://github.com/alfrej…
alfrejivi Mar 13, 2020
d77646a
.env.template sorting back
alfrejivi Mar 13, 2020
67fadf4
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 14, 2020
6ba4b60
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 15, 2020
8189f36
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 16, 2020
bf706f8
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 23, 2020
1b423a5
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 24, 2020
fc129fc
Header component calls fixed
alfrejivi Mar 24, 2020
b761d7c
Context API removed
alfrejivi Mar 24, 2020
2a08e8d
Context API related text removed from README
alfrejivi Mar 24, 2020
8d16e8c
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 24, 2020
7d54345
put everything back but getServerSideProps
alfrejivi Mar 25, 2020
7fe4971
Merge branch 'enhancement/auth0-example' of https://github.com/alfrej…
alfrejivi Mar 25, 2020
b775b53
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 25, 2020
5477e71
client side code removed from GSSP
alfrejivi Mar 25, 2020
f2d3928
merge changes
alfrejivi Mar 25, 2020
cd190fb
Merge branch 'canary' into enhancement/auth0-example
alfrejivi Mar 31, 2020
1fb4ae1
Updated comments
Mar 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/auth0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,6 @@ This sample tries to cover a few topics:
- Signing in
- Signing out
- Loading the user on the server side and adding it as part of SSR (`/pages/advanced/ssr-profile.js`)
- Loading the user on the client side and using fast/cached SSR pages (`/pages/index.js`)
- Loading the user on the client side and using fast/cached SSR pages (`/pages/profile.js`)
- API Routes which can load the current user (`/pages/api/me.js`)
- Using hooks to make the user available throughout the application (`/lib/user.js`)
- Using Context API and hooks to make the user available throughout the application (`/lib/user.js`, `/lib/authProvider.js`)
84 changes: 48 additions & 36 deletions examples/auth0/components/header.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,58 @@
import Link from 'next/link'
import { AuthContext } from '../lib/authProvider'
import { useContext } from 'react'

function Header({ SSRUser }) {
let { user } = useContext(AuthContext)
if (SSRUser) {
user = SSRUser
}

const authHeader = () => (
<>
<li>
<Link href="/profile">
<a>Client-rendered profile</a>
</Link>
</li>
<li>
<Link href="/advanced/ssr-profile">
<a>Server rendered profile (advanced)</a>
</Link>
</li>
<li>
<a href="/api/logout">Logout</a>
</li>
</>
)

const unAuthHeader = () => (
<>
<>
<li>
<Link href="/">
<a>Home</a>
</Link>
</li>
<li>
<Link href="/about">
<a>About</a>
</Link>
</li>
</>
<li>
<a href="/api/login">Login</a>
</li>
</>
)

function Header({ user, loading }) {
return (
<header>
<nav>
<ul>
<li>
<Link href="/">
<a>Home</a>
</Link>
</li>
<li>
<Link href="/about">
<a>About</a>
</Link>
</li>
{!loading &&
(user ? (
<>
<li>
<Link href="/profile">
<a>Client-rendered profile</a>
</Link>
</li>
<li>
<Link href="/advanced/ssr-profile">
<a>Server rendered profile (advanced)</a>
</Link>
</li>
<li>
<a href="/api/logout">Logout</a>
</li>
</>
) : (
<li>
<a href="/api/login">Login</a>
</li>
))}
</ul>
<ul>{user ? authHeader() : unAuthHeader()}</ul>
alfrejivi marked this conversation as resolved.
Show resolved Hide resolved
</nav>

<style jsx>{`
<style jsx global>{`
header {
padding: 0.2rem;
color: #fff;
Expand Down
36 changes: 17 additions & 19 deletions examples/auth0/components/layout.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import Head from 'next/head'
import Header from './header'

function Layout({ user, loading = false, children }) {
function Layout({ children }) {
return (
<>
<Head>
<title>Next.js with Auth0</title>
</Head>

<Header user={user} loading={loading} />

<Header />
<main>
<div className="container">{children}</div>
</main>

<style jsx>{`
.container {
max-width: 42rem;
margin: 1.5rem auto;
}
`}</style>
<style jsx global>{`
body {
margin: 0;
color: #333;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
`}</style>
<style jsx global>
{`
body {
margin: 0;
color: #333;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue',
sans-serif;
}
.container {
lfades marked this conversation as resolved.
Show resolved Hide resolved
max-width: 42rem;
margin: 1.5rem auto;
}
`}
</style>
</>
)
}
Expand Down
24 changes: 24 additions & 0 deletions examples/auth0/components/profile-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useContext } from 'react'
import { AuthContext } from '../lib/authProvider'

function ProfileCard({ SSRUser }) {
let { user, loading } = useContext(AuthContext)
if (SSRUser) {
user = SSRUser
}
if (loading) {
return <p>loading</p>
}
if (!user) {
return <></>
}
return (
<>
<img src={user.picture} alt="user picture" />
<p>nickname: {user.nickname}</p>
<p>name: {user.name}</p>
</>
)
}

export default ProfileCard
14 changes: 14 additions & 0 deletions examples/auth0/lib/authProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createContext } from 'react'
import { useFetchUser } from '../lib/user'
export const AuthContext = createContext({ user: null, loading: false })

function AuthProvider({ children }) {
const { user, loading } = useFetchUser()
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
)
}

export default AuthProvider
25 changes: 6 additions & 19 deletions examples/auth0/lib/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,26 @@ export async function fetchUser(cookie = '') {
if (typeof window !== 'undefined' && window.__user) {
return window.__user
}

const res = await fetch(
'/api/me',
cookie
? {
headers: {
cookie,
},
}
: {}
)

if (!res.ok) {
const response = await fetch('/api/me', cookie ? { headers: { cookie } } : {})
if (!response.ok) {
delete window.__user
return null
}

const json = await res.json()
const userData = await response.json()
if (typeof window !== 'undefined') {
window.__user = json
window.__user = userData
}
return json
return userData
}

export function useFetchUser({ required } = {}) {
export function useFetchUser({ required = false } = {}) {
const [loading, setLoading] = useState(
() => !(typeof window !== 'undefined' && window.__user)
)
const [user, setUser] = useState(() => {
if (typeof window === 'undefined') {
return null
}

return window.__user || null
})

Expand Down
25 changes: 12 additions & 13 deletions examples/auth0/pages/about.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import React from 'react'

import Layout from '../components/layout'
import { useFetchUser } from '../lib/user'
import AuthProvider from '../lib/authProvider'

function About() {
const { user, loading } = useFetchUser()

return (
<Layout user={user} loading={loading}>
<h1>About</h1>
<p>
This is the about page, navigating between this page and <i>Home</i> is
always pretty fast. However, when you navigate to the <i>Profile</i>{' '}
page it takes more time because it uses SSR to fetch the user first;
</p>
</Layout>
<AuthProvider>
<Layout>
<h1>About</h1>
<p>
This is the about page, navigating between this page and <i>Home</i>{' '}
is always pretty fast. However, when you navigate to the{' '}
<i>Profile</i> page it takes more time because it uses SSR to fetch
the user first;
</p>
</Layout>
</AuthProvider>
)
}

Expand Down
90 changes: 46 additions & 44 deletions examples/auth0/pages/advanced/ssr-profile.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,62 @@
import React from 'react'

// This import is only needed when checking authentication status directly from getInitialProps
// This import is only needed when checking authentication status directly from getServerSideProps
import auth0 from '../../lib/auth0'
import { fetchUser } from '../../lib/user'
import Layout from '../../components/layout'
import ProfileCard from '../../components/profile-card'
import Header from '../../components/header'
import Head from 'next/head'

function Profile({ user }) {
function SSRProfile({ user }) {
return (
<Layout user={user}>
<h1>Profile</h1>

<div>
<h3>Profile (server rendered)</h3>
<img src={user.picture} alt="user picture" />
<p>nickname: {user.nickname}</p>
<p>name: {user.name}</p>
</div>
</Layout>
<>
<Head>
<title>Next.js with Auth0</title>
</Head>
<Header SSRUser={user} />
<main>
<div className="container">
<h1>Profile (server rendered)</h1>
<ProfileCard SSRUser={user} />
</div>
</main>
<style jsx global>
{`
body {
margin: 0;
color: #333;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue',
sans-serif;
}

.container {
max-width: 42rem;
margin: 1.5rem auto;
}
`}
</style>
</>
)
}

Profile.getInitialProps = async ({ req, res }) => {
export async function getServerSideProps({ req, res }) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this function, remove anything that's not for the server, because getServerSideProps will only execute in the server, meaning anything that doesn't match typeof window === 'undefined'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol, I did that before, I forgot to leave it in the last commit

// On the server-side you can check authentication status directly
// However in general you might want to call API Routes to fetch data
// An example of directly checking authentication:
if (typeof window === 'undefined') {
const { user } = await auth0.getSession(req)
if (!user) {
res.writeHead(302, {
Location: '/api/login',
})
res.end()
return
}
return { user }
const session = await auth0.getSession(req)
if (!session || !session.user) {
res.writeHead(302, { Location: '/api/login' })
res.end()
return
}
return { props: { user: session.user } }

// To do fetches to API routes you can pass the cookie coming from the incoming request on to the fetch
// so that a request to the API is done on behalf of the user
// keep in mind that server-side fetches need a full URL, meaning that the full url has to be provided to the application
const cookie = req && req.headers.cookie
const user = await fetchUser(cookie)

// A redirect is needed to authenticate to Auth0
if (!user) {
if (typeof window === 'undefined') {
res.writeHead(302, {
Location: '/api/login',
})
return res.end()
}

window.location.href = '/api/login'
}

return { user }
// Exmaple:
/*
const cookie = req && req.headers.cookie
const response = await fetchSomeAPIRoute(cookie)
*/
}

export default Profile
export default SSRProfile
2 changes: 1 addition & 1 deletion examples/auth0/pages/api/callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import auth0 from '../../lib/auth0'

export default async function callback(req, res) {
try {
await auth0.handleCallback(req, res, { redirectTo: '/' })
await auth0.handleCallback(req, res, { redirectTo: '/profile' })
} catch (error) {
console.error(error)
res.status(error.status || 500).end(error.message)
Expand Down