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

feat: migrate to v4 #40

Merged
merged 30 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
90cef24
chore: bump nextjs to 11
ndom91 Jun 20, 2021
a52af26
Merge branch 'main' of ssh://github.com/nextauthjs/next-auth-example
ndom91 Aug 11, 2021
47a4866
feat: migrate to v4.0.0-next.20
ndom91 Aug 11, 2021
f80a7d3
fix: config comments
ndom91 Aug 11, 2021
e3f304a
fix: add nodemailer as manual dependency
ndom91 Aug 11, 2021
f1af1e2
feat: add ndom91 as contributor :grin:
ndom91 Aug 11, 2021
6b09ce7
fix: provider import
ndom91 Aug 11, 2021
a56e9c9
feat: update next-auth
ndom91 Aug 27, 2021
005958b
fix: add package-lock
ndom91 Aug 27, 2021
039930e
feat: update next-auth to v4-beta.1
ndom91 Sep 5, 2021
06b7ac9
fix: remove carrot
ndom91 Sep 5, 2021
10cbc2a
feat: upgrade to beta.2
ndom91 Sep 7, 2021
f7d2d3b
fix: filename typo
ndom91 Oct 23, 2021
db89e51
feat: add Next.js 12 Middleware example page
balazsorban44 Oct 27, 2021
abecbb1
chore: simplify Middleware
balazsorban44 Oct 27, 2021
55d872a
chore: revert
balazsorban44 Oct 27, 2021
3ca025a
chore(deps): ugprade `next-auth`
balazsorban44 Oct 29, 2021
daf174f
chore: change url check
balazsorban44 Oct 29, 2021
23e4481
chore: add logs, refactor middleware
balazsorban44 Oct 29, 2021
2cfe764
fix: use new theme option
balazsorban44 Oct 29, 2021
35121e5
Image url value must be quoted within a string template (#46)
goo32 Nov 23, 2021
85e3e52
chore: remove lock file
balazsorban44 Nov 23, 2021
21d7a3e
Merge branch 'ndom91/update-v4' of github.com:nextauthjs/next-auth-ex…
balazsorban44 Nov 23, 2021
dc5ba10
chore: update [email protected]
ndom91 Nov 23, 2021
867d6b1
fix: exact version
ndom91 Nov 26, 2021
86373fa
Update _middleware.js
balazsorban44 Nov 30, 2021
2e3994c
fix: comment out email adapter
ndom91 Dec 1, 2021
7db6a67
feat: [email protected]
ndom91 Dec 1, 2021
f8ee115
fix: cleanup options
ndom91 Dec 1, 2021
3ff32ca
fix: rm sqlite3
ndom91 Dec 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
2 changes: 1 addition & 1 deletion components/access-denied.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { signIn } from 'next-auth/client'
import { signIn } from 'next-auth/react'

export default function AccessDenied () {
return (
Expand Down
88 changes: 65 additions & 23 deletions components/header.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
import Link from 'next/link'
import { signIn, signOut, useSession } from 'next-auth/client'
import styles from './header.module.css'
import Link from "next/link"
import { signIn, signOut, useSession } from "next-auth/react"
import styles from "./header.module.css"

// The approach used in this component shows how to built a sign in and sign out
// component that works on pages which support both client and server side
// rendering, and avoids any flash incorrect content on initial page load.
export default function Header () {
const [ session, loading ] = useSession()

export default function Header() {
const { data: session, status } = useSession()
const loading = status === "loading"

return (
<header>
<noscript>
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
</noscript>
<div className={styles.signedInStatus}>
<p className={`nojs-show ${(!session && loading) ? styles.loading : styles.loaded}`}>
{!session && <>
<span className={styles.notSignedInText}>You are not signed in</span>
<a
<p
className={`nojs-show ${
!session && loading ? styles.loading : styles.loaded
}`}
>
{!session && (
<>
<span className={styles.notSignedInText}>
You are not signed in
</span>
<a
href={`/api/auth/signin`}
className={styles.buttonPrimary}
onClick={(e) => {
Expand All @@ -27,14 +35,22 @@ export default function Header () {
>
Sign in
</a>
</>}
{session && <>
{session.user.image && <span style={{backgroundImage: `url(${session.user.image})` }} className={styles.avatar}/>}
<span className={styles.signedInText}>
<small>Signed in as</small><br/>
<strong>{session.user.email || session.user.name}</strong>
</>
)}
{session && (
<>
{session.user.image && (
<span
style={{ backgroundImage: `url('${session.user.image}')` }}
className={styles.avatar}
/>
)}
<span className={styles.signedInText}>
<small>Signed in as</small>
<br />
<strong>{session.user.email || session.user.name}</strong>
</span>
<a
<a
href={`/api/auth/signout`}
className={styles.button}
onClick={(e) => {
Expand All @@ -44,16 +60,42 @@ export default function Header () {
>
Sign out
</a>
</>}
</>
)}
</p>
</div>
<nav>
<ul className={styles.navItems}>
<li className={styles.navItem}><Link href="/"><a>Home</a></Link></li>
<li className={styles.navItem}><Link href="/client"><a>Client</a></Link></li>
<li className={styles.navItem}><Link href="/server"><a>Server</a></Link></li>
<li className={styles.navItem}><Link href="/protected"><a>Protected</a></Link></li>
<li className={styles.navItem}><Link href="/api-example"><a>API</a></Link></li>
<li className={styles.navItem}>
<Link href="/">
<a>Home</a>
</Link>
</li>
<li className={styles.navItem}>
<Link href="/client">
<a>Client</a>
</Link>
</li>
<li className={styles.navItem}>
<Link href="/server">
<a>Server</a>
</Link>
</li>
<li className={styles.navItem}>
<Link href="/protected">
<a>Protected</a>
</Link>
</li>
<li className={styles.navItem}>
<Link href="/api-example">
<a>API</a>
</Link>
</li>
<li className={styles.navItem}>
<Link href="/middleware-protected">
<a>Middleware protected</a>
</Link>
</li>
</ul>
</nav>
</header>
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
},
"author": "Iain Collins <[email protected]>",
"contributors": [
"Balázs Orbán <[email protected]>"
"Balázs Orbán <[email protected]>",
"Nico Domino <[email protected]>"
],
"license": "ISC",
"dependencies": {
"next": "^11.0.0",
"next-auth": "latest",
"next": "^12.0.1",
"next-auth": "^4.0.1",
"nodemailer": "^6.6.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"sqlite3": "^5.0.2"
"react-dom": "^17.0.2"
}
}
18 changes: 9 additions & 9 deletions pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import { Provider } from 'next-auth/client'
import { SessionProvider } from 'next-auth/react'
import './styles.css'

// Use the <Provider> to improve performance and allow components that call
// Use of the <SessionProvider> is now mandatory to allow components that call
// `useSession()` anywhere in your application to access the `session` object.
export default function App ({ Component, pageProps }) {
return (
<Provider
<SessionProvider
// Provider options are not required but can be useful in situations where
// you have a short session maxAge time. Shown here with default values.
options={{
// Client Max Age controls how often the useSession in the client should
// Stale Time controls how often the useSession in the client should
// contact the server to sync the session state. Value in seconds.
// e.g.
// * 0 - Disabled (always use cache value)
// * 60 - Sync session state with server if it's older than 60 seconds
clientMaxAge: 0,
// Keep Alive tells windows / tabs that are signed in to keep sending
staleTime: 0,
// Refetch Interval tells windows / tabs that are signed in to keep sending
// a keep alive request (which extends the current session expiry) to
// prevent sessions in open windows from expiring. Value in seconds.
//
// Note: If a session has expired when keep alive is triggered, all open
// windows / tabs will be updated to reflect the user is signed out.
keepAlive: 0
refetchInterval: 0
}}
session={pageProps.session} >
<Component {...pageProps} />
</Provider>
</SessionProvider>
)
}
}
13 changes: 13 additions & 0 deletions pages/_middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getToken } from "next-auth/jwt"
import { NextResponse } from "next/server"

/** @param {import("next/server").NextRequest} req */
export async function middleware(req) {
if (req.nextUrl.pathname === "/middleware-protected") {
const session = await getToken({ req, secret: process.env.SECRET })
// You could also check for any property on the session object,
// like role === "admin" or name === "John Doe", etc.
if (!session) return NextResponse.redirect("/api/auth/signin")
// If user is authenticated, continue.
}
}
55 changes: 28 additions & 27 deletions pages/api/auth/[...nextauth].js
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import GoogleProvider from "next-auth/providers/google"
import FacebookProvider from "next-auth/providers/facebook"
import GithubProvider from "next-auth/providers/github"
import TwitterProvider from "next-auth/providers/twitter"
import Auth0Provider from "next-auth/providers/auth0"
// import AppleProvider from "next-auth/providers/apple"
// import EmailProvider from "next-auth/providers/email"

// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [
Providers.Email({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
}),
/* EmailProvider({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
}),
// Temporarily removing the Apple provider from the demo site as the
// callback URL for it needs updating due to Vercel changing domains
/*
Providers.Apple({
clientId: process.env.APPLE_ID,
clientSecret: {
Expand All @@ -23,38 +29,30 @@ export default NextAuth({
},
}),
*/
Providers.Facebook({
FacebookProvider({
clientId: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
}),
Providers.GitHub({
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
// https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps
scope: "read:user"
scope: "read:user",
}),
Providers.Google({
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
Providers.Twitter({
TwitterProvider({
clientId: process.env.TWITTER_ID,
clientSecret: process.env.TWITTER_SECRET,
}),
Providers.Auth0({
Auth0Provider({
clientId: process.env.AUTH0_ID,
clientSecret: process.env.AUTH0_SECRET,
domain: process.env.AUTH0_DOMAIN,
}),
],
// Database optional. MySQL, Maria DB, Postgres and MongoDB are supported.
// https://next-auth.js.org/configuration/databases
//
// Notes:
// * You must install an appropriate node_module for your database
// * The Email provider requires a database (OAuth providers do not)
database: process.env.DATABASE_URL,

// The secret should be set to a reasonably long random string.
// It is used to sign cookies and to sign and encrypt JSON Web Tokens, unless
// a separate secret is defined explicitly for encrypting the JWT.
Expand All @@ -63,8 +61,8 @@ export default NextAuth({
session: {
// Use JSON Web Tokens for session instead of database sessions.
// This option can be used with or without a database for users/accounts.
// Note: `jwt` is automatically set to `true` if no database is specified.
jwt: true,
// Note: `strategy` should be set to 'jwt' if no database is used.
strategy: 'jwt'

// Seconds - How long until an idle session expires and is no longer valid.
// maxAge: 30 * 24 * 60 * 60, // 30 days
Expand All @@ -81,6 +79,7 @@ export default NextAuth({
jwt: {
// A secret to use for key generation (you should set this explicitly)
// secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnw',
secret: process.env.SECRET,
// Set to true to use encryption (default: false)
// encryption: true,
// You can define your own encode/decode functions for signing and encryption
Expand All @@ -106,10 +105,10 @@ export default NextAuth({
// when an action is performed.
// https://next-auth.js.org/configuration/callbacks
callbacks: {
// async signIn(user, account, profile) { return true },
// async redirect(url, baseUrl) { return baseUrl },
// async session(session, user) { return session },
// async jwt(token, user, account, profile, isNewUser) { return token }
// async signIn({ user, account, profile, email, credentials }) { return true },
// async redirect({ url, baseUrl }) { return baseUrl },
// async session({ session, token, user }) { return session },
// async jwt({ token, user, account, profile, isNewUser }) { return token }
},

// Events are useful for logging
Expand All @@ -118,7 +117,9 @@ export default NextAuth({

// You can set the theme to 'light', 'dark' or use 'auto' to default to the
// whatever prefers-color-scheme is set to in the browser. Default is 'auto'
theme: 'light',
theme: {
colorScheme: "light",
},

// Enable debug messages in the console if you are having problems
debug: false,
Expand Down
4 changes: 2 additions & 2 deletions pages/api/examples/jwt.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// This is an example of how to read a JSON Web Token from an API route
import jwt from 'next-auth/jwt'
import { getToken } from 'next-auth/jwt'

const secret = process.env.SECRET

export default async (req, res) => {
const token = await jwt.getToken({ req, secret })
const token = await getToken({ req, secret })
res.send(JSON.stringify(token, null, 2))
}
4 changes: 2 additions & 2 deletions pages/api/examples/protected.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This is an example of to protect an API route
import { getSession } from 'next-auth/client'
import { getSession } from 'next-auth/react'

export default async (req, res) => {
const session = await getSession({ req })
Expand All @@ -9,4 +9,4 @@ export default async (req, res) => {
} else {
res.send({ error: 'You must be sign in to view the protected content on this page.' })
}
}
}
4 changes: 2 additions & 2 deletions pages/api/examples/session.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// This is an example of how to access a session from an API route
import { getSession } from 'next-auth/client'
import { getSession } from 'next-auth/react'

export default async (req, res) => {
const session = await getSession({ req })
res.send(JSON.stringify(session, null, 2))
}
}
9 changes: 9 additions & 0 deletions pages/middleware-protected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Layout from "../components/layout"

export default function Page() {
return (
<Layout>
<h1>Page protected by Middleware</h1>
</Layout>
)
}
7 changes: 4 additions & 3 deletions pages/protected.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useState, useEffect } from 'react'
import { useSession } from 'next-auth/client'
import { useSession } from 'next-auth/react'
import Layout from '../components/layout'
import AccessDenied from '../components/access-denied'

export default function Page () {
const [ session, loading ] = useSession()
const { data: session, status } = useSession()
const loading = status === 'loading'
const [ content , setContent ] = useState()

// Fetch content from protected route
Expand All @@ -30,4 +31,4 @@ export default function Page () {
<p><strong>{content || "\u00a0"}</strong></p>
</Layout>
)
}
}
Loading