Mohammad Khan
Mohammad Khan

Reputation: 363

Protect Routes/Pages with NextJs

I have a simple project that I built that protects the routes/pages of the website by using the if and else statement and putting each page with a function withAuth(), but I'm not sure if that is the best way to protect routes with nextjs, and I noticed that there is a delay in protecting the route or pages, like 2-3 seconds long, in which they can see the content of the page before it redirects the visitor or unregistered user to the login page.

Is there a way to get rid of it or make the request faster so that unregistered users don't view the page's content? Is there a better approach to safeguard a certain route in the nextjs framework?

Code


import { useContext, useEffect } from "react";
import { AuthContext } from "@context/auth";
import Router from "next/router";

const withAuth = (Component) => {
  const Auth = (props) => {
    const { user } = useContext(AuthContext);

    useEffect(() => {
      if (!user) Router.push("/login");
    });

    return <Component {...props} />;
  };

  return Auth;
};

export default withAuth;

Sample of the use of withAuth

import React from "react";
import withAuth from "./withAuth";

function sample() {
  return <div>This is a protected page</div>;
}

export default withAuth(sample);

Upvotes: 1

Views: 12133

Answers (2)

Ahmet Firat Keler
Ahmet Firat Keler

Reputation: 4021

With Customized 401 Page

We are going to first define our customized 401 page

import React from "react"

const Page401 = () => {
    return (
        <React.Fragment>
            //code of your customized 401 page
        </React.Fragment>
    )
}

export default Page401

Now, we are going to change a small part of the code kiranr shared

export async function getServerSideProps({ req }) {

    const { token } = cookie.parse(req.headers.cookie)

    const userRes = await fetch(`${URL}/api/user`, {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${token}`
        }
    })

    const data = await userRes.json()

    // does not allow access to page if not logged in 
    if (!data.username) {
        //THIS PART CHANGES
        return {
            props: {
                unauthorized: true
            }
        }
        //THIS PART CHANGES
    }

    return {
        props: { data }
    }
}

Then we will check this 'unauthorized' property in our _app.js file and call our customized 401 page component if its value is true

import Page401 from "../components/Error/Server/401/index";

const App = ({ Component, pageProps }) => {
    //code..
    if (pageProps.unauthorized) {
        //if code block reaches here then it means the user is not authorized
        return <Page401 />;
    }
    //code..

    //if code block reaches here then it means the user is authorized
    return (
        <Provider store={store}>
            <Component {...pageProps} />
        </Provider>
    )
}

Upvotes: 2

kiranr
kiranr

Reputation: 2465

you can make the authentication of user on server-side, if a user is logged in then show them the content of the protected route else redirect them to some other route. refer to this page for mote info.

in getServerSideProps check whether the user has logged in

   if (!data.username) {
        return {
            redirect: {
                destination: '/accounts/login',
                permanent: false,
            },
        }
    }

here's complete example of protected route page

export default function SomeComponent() {
    // some content
}

export async function getServerSideProps({ req }) {

    const { token } = cookie.parse(req.headers.cookie)

    const userRes = await fetch(`${URL}/api/user`, {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${token}`
        }
    })

    const data = await userRes.json()

    // does not allow access to page if not logged in 
    if (!data.username) {
        return {
            redirect: {
                destination: '/accounts/login',
                permanent: false,
            },
        }
    }

    return {
        props: { data }
    }
}

Upvotes: 6

Related Questions