Route guards in Next.js + react

18,058

Solution 1

You can check in getInitialProps with some approp. logic evaluating the cookies to decide whether to redirect or not.

import Router from 'next/router'

const redirectToLogin = res => {  
  if (res) {
    res.writeHead(302, {Location: '/login'})
    res.end()
    res.finished = true
  } else {
    Router.push('/login')
  }
}


class ProtectedPage extends React.Component {
  static async getInitialProps ({req, res}) {
    // get cookie from req.headers or from document.cookie in browser
    // this cookie must not contain sensitive information!
    const profile = getProfileFromCookie(req)
    if (!profile) {
      redirectToLogin(res)
    }
  }
}

Have a look at this sample code https://github.com/lipp/login-with/blob/master/example/nextjs/with-profile.js#L8 (I am the author).

Solution 2

I've had a lot of issues with this, but eventually succeeded to figure things out.

Im using apollo, and my problem was, that I had to redirect on the server if the user is not logged in, or doesn't have a particular role. This is how its done, maybe it helps you too:

import { gql } from 'apollo-boost'
import initApollo from '~/config/init-apollo'
import { Role } from '~/generated/apollo-components'
import { NextPage } from '~/node_modules/next'
import redirect from '~/utils/redirect'
import { parseCookies } from '~/utils/with-apollo'


const GET_USER_ROLE = gql`
    query {
        me {
            role
        }
    }
`

export default (Page: NextPage<any>, allow: Role[]) => {
  const originalGetInitialProps = Page.getInitialProps
  let pageProps = {}

  Page.getInitialProps = async (ctx) => {
    if (originalGetInitialProps) {
      pageProps = await originalGetInitialProps(ctx)
    }

    const apolloClient = initApollo(
      {},
      { getToken: () => parseCookies(ctx.req).token },
    )

    try {
      const { data } = await apolloClient.query({ query: GET_USER_ROLE })

      if (!allow.includes(data.me.role as Role)) {
        redirect(ctx, '/401')
      }

      return {
        ...pageProps,
      }
    } catch (e) {
      console.log('error: ', e.graphQLErrors[0])
      redirect(ctx, '/login')
    }
  }

  return Page
}
Share:
18,058
Артем Мирошниченко
Author by

Артем Мирошниченко

Updated on June 04, 2022

Comments

  • Артем Мирошниченко
    Артем Мирошниченко almost 2 years

    I have a have a project on Next.js and React, which doesn't use any libraries for routing. How should I implement route guards (protected routes) for non-authenticated users? Or should I just redirect them if there is no token in cookie?

  • Артем Мирошниченко
    Артем Мирошниченко almost 6 years
    Great idea ! Thank you !
  • Omri Btian
    Omri Btian about 4 years
    what about all the nested routes below the protectedPage?