Implementing route protection
I tried implementing route protection in nextjs 13.4.4 but did not work as a user signs in but is not redirected to the protected pages , below is the codes
privateroute.tsx
import { Spinner } from "@chakra-ui/react";
import { redirect, usePathname } from "next/navigation";
import { useUser } from "./middleware";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const WithPrivateRoute = (Component: React.FunctionComponent<any>) => {
const NewComponent = () => {
const { user, isLoading } = useUser();
// if (isLoading) return <Spinner />;
if (!user) redirect("/");
return <Component />;
};
return NewComponent;
};
import { Spinner } from "@chakra-ui/react";
import { redirect, usePathname } from "next/navigation";
import { useUser } from "./middleware";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const WithPrivateRoute = (Component: React.FunctionComponent<any>) => {
const NewComponent = () => {
const { user, isLoading } = useUser();
// if (isLoading) return <Spinner />;
if (!user) redirect("/");
return <Component />;
};
return NewComponent;
};
1 Reply
middleware.tsx
layout.tsx
import React, { createContext, useContext, useEffect, useState } from "react";
import type { Session, User } from "@supabase/supabase-js";
import { supabase } from "@/app/libs/supabase";
export const AuthContext = createContext<{
user: User | null;
session: Session | null;
isLoading: boolean;
}>({
user: null,
session: null,
isLoading: true,
});
export const AuthContextProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [userSession, setUserSession] = useState<Session | null>(null);
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
void supabase.auth.getSession().then(({ data: { session } }) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
});
const { data: authListener } = supabase.auth.onAuthStateChange(
(event, session) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
}
);
return () => {
authListener.subscription.unsubscribe();
};
}, []);
const value = {
session: userSession,
user,
isLoading,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useUser = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useUser must be used within a AuthContextProvider.");
}
return context;
};
import React, { createContext, useContext, useEffect, useState } from "react";
import type { Session, User } from "@supabase/supabase-js";
import { supabase } from "@/app/libs/supabase";
export const AuthContext = createContext<{
user: User | null;
session: Session | null;
isLoading: boolean;
}>({
user: null,
session: null,
isLoading: true,
});
export const AuthContextProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [userSession, setUserSession] = useState<Session | null>(null);
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
void supabase.auth.getSession().then(({ data: { session } }) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
});
const { data: authListener } = supabase.auth.onAuthStateChange(
(event, session) => {
setUserSession(session);
setUser(session?.user ?? null);
setIsLoading(false);
}
);
return () => {
authListener.subscription.unsubscribe();
};
}, []);
const value = {
session: userSession,
user,
isLoading,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useUser = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useUser must be used within a AuthContextProvider.");
}
return context;
};
"use client"
// import Menu from "./menu"
import Navbar from "@/components/NavBar/Navbar"
import ClientOnly from "../../components/hydra/Hydra"
function RootLayout({children}
: {
children: React.ReactNode
}){
return (
<section>
<ClientOnly>
<main><Navbar/>{children}</main></ClientOnly>
</section>
)
}
export default WithPrivateRoute(RootLayout)
"use client"
// import Menu from "./menu"
import Navbar from "@/components/NavBar/Navbar"
import ClientOnly from "../../components/hydra/Hydra"
function RootLayout({children}
: {
children: React.ReactNode
}){
return (
<section>
<ClientOnly>
<main><Navbar/>{children}</main></ClientOnly>
</section>
)
}
export default WithPrivateRoute(RootLayout)