This guide will help you migrate from 1.x to 2.x of the Auth0 Next.js SDK.
Node 10 No Longer Supported
Node 12 LTS and newer LTS releases are supported. Node 10 is no longer supported.
getSession Now Returns a Promise
getSession is now asynchronous and returns a Promise.
// /pages/api/my-api
import { getSession } from "@auth0/nextjs-auth0"
function myApiRoute(req, res) {
const session = getSession(req, res)
// ...
}
// /pages/api/my-api
import { getSession } from "@auth0/nextjs-auth0"
async function myApiRoute(req, res) {
const session = await getSession(req, res)
// ...
}
Client Methods and Components Now Exported Under /client
All methods and components for the browser should now be accessed under /client.
// pages/_app.js
import React from "react"
import { UserProvider } from "@auth0/nextjs-auth0"
export default function App({ Component, pageProps }) {
return (
<UserProvider>
<Component {...pageProps} />
</UserProvider>
)
}
// pages/index.js
import { useUser } from "@auth0/nextjs-auth0"
export default function Index() {
const { user, error, isLoading } = useUser()
if (isLoading) return <div>Loading...</div>
if (error) return <div>{error.message}</div>
if (user) {
return (
<div>
Welcome {user.name}! <a href="/api/auth/logout">Logout</a>
</div>
)
}
return <a href="/api/auth/login">Login</a>
}
// pages/_app.js
import React from "react"
import { UserProvider } from "@auth0/nextjs-auth0/client"
export default function App({ Component, pageProps }) {
return (
<UserProvider>
<Component {...pageProps} />
</UserProvider>
)
}
// pages/index.js
// The SSR version of withPageAuthRequired is still in the root export
import { withPageAuthRequired as withPageAuthRequiredSSR } from "@auth0/nextjs-auth0"
import {
useUser,
withPageAuthRequired as withPageAuthRequiredCSR,
} from "@auth0/nextjs-auth0/client"
export default withPageAuthRequiredCSR(function Index() {
const { user, error, isLoading } = useUser()
if (isLoading) return <div>Loading...</div>
if (error) return <div>{error.message}</div>
if (user) {
return (
<div>
Welcome {user.name}! <a href="/api/auth/logout">Logout</a>
</div>
)
}
return <a href="/api/auth/login">Login</a>
})
export const getServerSideProps = withPageAuthRequiredSSR()
updateSession Has Been Added
Session modifications are no longer saved implicitly. You must explicitly call updateSession to persist changes.
Previously your application could make modifications to the session during the lifecycle of the request and those updates would be saved implicitly when the response’s headers were written:// /pages/api/update-user
import { getSession } from "@auth0/nextjs-auth0"
function myApiRoute(req, res) {
const session = getSession(req, res)
session.foo = "bar"
res.json({ success: true })
}
// The updated session is serialized and the cookie is updated
// when the cookie headers are written to the response.
We’ve introduced a new updateSession method which must be explicitly invoked in order to update the session. This will immediately serialize the session, write it to the cookie and return a Promise.// /pages/api/update-user
import { getSession, updateSession } from "@auth0/nextjs-auth0"
async function myApiRoute(req, res) {
const session = await getSession(req, res)
// The session is updated, serialized and the cookie is updated
// everytime you call `updateSession`.
await updateSession(req, res, {
...session,
user: { ...session.user, foo: "bar" },
})
res.json({ success: true })
}
getServerSidePropsWrapper Has Been Removed
getServerSidePropsWrapper is no longer needed and has been removed.
Because the process of modifying the session is now explicit, you no longer have to wrap getServerSideProps in getServerSidePropsWrapper.
export const getServerSideProps = getServerSidePropsWrapper((ctx) => {
const session = getSession(ctx.req, ctx.res)
if (session) {
// User is authenticated
} else {
// User is not authenticated
}
})
export const getServerSideProps = async (ctx) => {
const session = await getSession(ctx.req, ctx.res)
if (session) {
// User is authenticated
} else {
// User is not authenticated
}
}
Profile API Route No Longer Returns a 401
The profile API route now returns a 204 status code when the user is not authenticated instead of 401.
Previously the profile API route, by default at /api/auth/me, would return a 401 error when the user was not authenticated. While it was technically the right status code for the situation, it showed up in the browser console as an error. This API route will now return a 204 instead. Since 204 is a successful status code, it will not produce a console error.
Override Default Error Handler
You can now set the default error handler for the auth routes in a single place.
export default handleAuth({
async login(req, res) {
try {
await handleLogin(req, res)
} catch (error) {
errorLogger(error)
res.status(error.status || 500).end()
}
},
async callback(req, res) {
try {
await handleLogin(req, res)
} catch (error) {
errorLogger(error)
res.status(error.status || 500).end()
}
},
// ...
})
export default handleAuth({
onError(req, res, error) {
errorLogger(error)
// You can finish the response yourself if you want to customize
// the status code or redirect the user
// res.writeHead(302, {
// Location: '/custom-error-page'
// });
// res.end();
},
})
afterCallback Can Write to the Response
You can now write your own redirect header or terminate the request in afterCallback.
const afterCallback = (req, res, session, state) => {
if (session.user.isAdmin) {
return session;
} else {
res.status(401).end('User is not admin');
}
}; // 💥 Fails with ERR_HTTP_HEADERS_SENT
const afterCallback = (req, res, session, state) => {
if (!session.user.isAdmin) {
res.setHeader('Location', '/admin');
}
return session;
}; // 💥 Fails with ERR_HTTP_HEADERS_SENT
const afterCallback = (req, res, session, state) => {
if (session.user.isAdmin) {
return session;
} else {
res.status(401).end('User is not admin');
}
}; // Terminates the request with 401 if user is not admin
const afterCallback = (req, res, session, state) => {
if (!session.user.isAdmin) {
res.setHeader('Location', '/admin');
}
return session;
}; // Redirects to `/admin` if user is admin
Previously it was not possible to configure the default handlers. For example, to pass a connection parameter to the login handler, you had to override it.
export default handleAuth({
login: async (req, res) => {
try {
await handleLogin(req, res, {
authorizationParams: { connection: "github" },
})
} catch (error) {
// ...
}
},
})
Now you can configure a default handler by passing an options object to it:export default handleAuth({
login: handleLogin({
authorizationParams: { connection: "github" },
}),
})
You can also pass a function that receives the request and returns an options object:export default handleAuth({
login: handleLogin((req) => {
return {
authorizationParams: { connection: "github" },
}
}),
})
You can even create new handlers by configuring the default ones:export default handleAuth({
// Creates /api/auth/signup
signup: handleLogin({
authorizationParams: { screen_hint: "signup" },
}),
})
It is still possible to override the default handlers if needed.