Route guards in Next.js + react

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?

Upvotes: 10

Views: 23232

Answers (3)

monfrik
monfrik

Reputation: 1

You can use the https://www.npmjs.com/package/next-router-guards library. There, you can customize the access settings for your pages using the existing protection options, or create your own protection with custom logic. If you want to check if a user is authorized with a token, you can use AuthorizedGuard (example https://github.com/makskiyko/next-router-guards/blob/master/exmaples/AuthorizedGuard.md)

Upvotes: 0

Daniel Tok
Daniel Tok

Reputation: 217

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
}

Upvotes: 2

lipp
lipp

Reputation: 5926

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).

Upvotes: 11

Related Questions