Auth redirect in NextJS

A K
3 min readDec 18, 2019

--

A simplified authentication wrapper for universal apps

I have an exciting new project, which means this entire week gets dedicated to the best worst part of my job: catching up with the latest and greatest with my favorite tools and how the heck I can smush them all together.

The challenge

Preventing unauthorized navigation to a page is an aspect of NextJS that seems to have flummoxed even the best of us at some point. It’s complicated to begin with because the solution must handle client-side Router and server-side { req, res }. Implementing with a HOC or hook within a page flashes forbidden content or a dead view before the redirect kicks in. Sometimes you can use getInitialProps(), but not if you also want static pages. Hmmm.

Courtesy of Bich Tran, pexels.com/@thngocbich

Auth0 is the project’s user authentication & authorization solution, implemented as recommended by the semi-official @auth0/nextjs-auth0 SDK. It’s an experimental project but already enshrined as the auth0 example given in the NextJS repo.

The solution also has to play nice with Apollo Client, which currently uses a HOC for graphql-powered pages. Even without SSR, it gets messy.

Prereqs

We need a way to access the auth information client-side from an HttpOnly cookie. For simplicity, let’s just make use of the handleProfile method provided by the Auth0 SDK:

/pages/api/me.js

A humble wrapper

Getting to the point: we need something that can listen for both app router and auth information, and prevent users from either navigating to or landing on a protected page. We’re keeping this demo simple by assuming that the landing page, /, is the only public page. All others require authentication.

Let’s create an AuthProvider, a React Context, that monitors the user’s auth status (yes or no) and sends the public information to the rest of the app:

Why does Medium keep cutting off Gists?

Look at the key pieces section by section. We have a function for getting the user profile, if it exists, from our API route:

  async function getUser() {
try {
const response = await fetch('/api/me')
const profile = await response.json()
if (profile.error) {
setUser(null)
} else {
setUser(profile)
}
} catch (err) {
console.error(err)
}
}

We check the user’s auth with every route change:

  useEffect(() => {
getUser()
}, [pathname])

And then we see if the user is trying to get somewhere they shouldn’t be, we can boot them back to the public landing page right at the start of the navigation process:

  useEffect(() => {
// Check that a new route is OK
const handleRouteChange = url => {
if (url !== '/' && !user) {
window.location.href = '/'
}
}
// Check that initial route is OK
if (pathname !== '/' && user === null) {
window.location.href = '/'
}
// Monitor routes
events.on('routeChangeStart', handleRouteChange)
return () => {
events.off('routeChangeStart', handleRouteChange)
}
}, [user])

We then implement AuthWrapper the same way we do Layout:

Ta daaa

This is a basic demo, but pretty easy to customize and extend. It even provides the user’s Auth0 profile info in a way that’s accessible to other key parts of the app, like a personalized greeting in the Layout, while keeping things secure. We can even keep our secured pages static pre-rendered, since this solution does not rely on getInitialProps. Huzzah!

Upcoming

The NextJS + Apollo + Auth0 combination is in a state of flux right now, with interesting things on the horizon. NextJS has opened up RFC’s for better static generation and webpack plugins. Apollo Client 3.0 is in beta, reorganizing the core components and hopefully tidying up. And authentication in general is having a moment, with the session vs refresh_token debate and its complex implications for universal apps. Much to monitor. But also kinda fun.

Update

Thanks to John Serrao for pointing out the similar useAuth package for GatsbyJS, very cool batteries-included option. Great inspiration!

--

--