I am currently working on user authentication and authorization in next.js. I created a custom authguard hook, and it is working fine. But the problem arises when user refreshes the page after login, it is redirected to login page.
AuthGuard Flow:- If the user is not authenticated it will redirect them to login page and if the user is authenticated it should not redirect them to login when user refreshes the page(But currently it is redirecting to login page after page refresh).
Complete Flow:- There are some protected pages in my project like dashboard, protected, where user can't enter without login. After login, the server sends the access token and refresh token to the client. Access token is stored in memory and refresh token in HTTPS secure cookie. A new access token is sent to the client whenever the user refresh the page.
How to solve this problem(Also if you have better approach to work with authorization in next.js then let me know)?
Code to Repo:- https://github.com/Sumukha210/next.js-authentication
AuthGuard:-
import { useRouter } from "next/router";
import { useEffect } from "react";
import useStore from "../context/store";
const useAuthGuard = () => {
const isAuthenticated = useStore(s => s.isAuthenticated);
const loading = useStore(s => s.loading);
const router = useRouter();
useEffect(() => {
if (!loading && !isAuthenticated) {
router.replace("/auth/login");
}
}, [isAuthenticated, loading]);
const ProtectedComponent: React.FC = ({ children }) => {
if (loading) {
return <p>Loading...</p>;
}
return <div>{isAuthenticated ? children : <></>}</div>;
};
return [ProtectedComponent];
};
export default useAuthGuard;
store.ts:-
import create from "zustand";
import { devtools } from "zustand/middleware";
type roleType = "user" | "admin";
enum AccessLevel {
USER = "CODE 234",
EDITOR = "CODE 134",
ADMIN = "CODE 34",
}
type useStoreTypes = {
isAuthenticated: boolean;
role: roleType;
accessToken: null | string;
loading: boolean;
changeRole: (type: roleType) => void;
setAccessToken: (val: string | null) => void;
setLoading: (val: boolean) => void;
};
const useStore = create<useStoreTypes>(
devtools(
(set): useStoreTypes => ({
isAuthenticated: false,
role: "user",
accessToken: null,
loading: false,
changeRole(type) {
set(() => ({ role: type }));
},
setAccessToken(val) {
set(() => ({ accessToken: val, isAuthenticated: val ? true : false }));
},
setLoading(val) {
set(() => ({ loading: val }));
},
}),
{ name: "authStore" }
)
);
export default useStore;