I want to wrap my whole application so that it is not accessible unless the user is logged in. I managed to redirect the user to the login page if the user is not logged in, however, i still see a flash of the private route before the redirection occurs. How can this be avoided?
-
possible duplicate of https://stackoverflow.com/questions/64662486/how-do-you-deal-with-public-and-private-routes-in-a-nextjs-app/64686516#64686516 – Andrew Zheng Mar 21 '21 at 01:28
-
Yes @AndrewZheng i tried that approach but for some reason, i still see a flash of the private page before it redirects – poca Mar 21 '21 at 01:55
-
@poca I always do this with swr which blocks rendering until the condition is met. I get the user authenticated with swr and check if the user exists or not then I redirect – enoch Mar 21 '21 at 03:10
1 Answers
Because NextJS is server-side rendered, you either need to check the authentication with getServerSideProps
or display a loading indicator on the front-end before the redirect.
Checking authentication client-side
Create a wrapper component and put it inside your _app.js
file. By showing a loading component while the user is still being authenticated, you prevent the private dashboard from showing. And note: because Next.js is server-side rendered, the HTML will always show up before the JS is rehydrated. That means, first paint will always occur before the redirect starts.
import { useRouter } from 'next/router'
export const AuthCheck = (props) => {
const router = useRouter()
const user = useUser() // you need to implement this. In this example, undefined means things are still loading, null means user is not signed in, anything truthy means they're signed in
if (typeof window !== 'undefined' && user === null) router.push('/sign-in')
if(!user) return <Loading /> // a loading component that prevents the page from rendering
return props.children
}
Then in your _app.js
const MyApp = ({ Component, pageProps }) => {
return (
<AuthCheck>
<Component {...pageProps} />
</AuthCheck>
)
}
export default MyApp
Checking authentication server-side
Assuming you already have code setup to check authentication server-side, you can use this pattern. Note: you'll need to add this to every single page. getServerSideProps
does not work with _app.js
or _document.js
export const getServerSideProps = async () => {
const isAuthenticated = await checkAuthentication() // you need to implement this
if (!isAuthenticated) {
return {
redirect: { destination: '/sign-in', permanent: false },
}
}
}

- 504
- 5
- 19

- 5,108
- 2
- 25
- 58
-
Thanks Nick!, but after implementing this i get the following error: 'Error: No router instance found. you should only use "next/router" inside the client side of your app. https://err.sh/vercel/next.js/no-router-instance' – poca Mar 21 '21 at 03:49
-
You're right, forgot to add the check to see if the code is running in the browser. Updating the answer now. – Nick Mar 21 '21 at 03:55
-
1The solution provided for checking the authentication on the client-side would always take the user to `/sign-in` even if the user tries to navigate to a page that is public (the user doesn't have to sign in). For example, if I want to navigate to `sign-up`, this condition will kick in and take me to `/sign-in`. It also blocks the 404 route recognition. Problem one can be solved by providing an array of public routes but doesn't seem like a clean solution – shet_tayyy Apr 15 '22 at 11:29