Home > Software engineering >  How can I specify authentication globally instead of defining on every page in Next js, I am using n
How can I specify authentication globally instead of defining on every page in Next js, I am using n

Time:04-03

Right now, I am using authentication on every page but I want to define it globally in _app.tsx file.

Now, my component

const Home: NextPage = () => {
  const { session, loading } = useAuth();

  
  if (!session) {
    return <UnAuthenticated />
  }

  return (
   <p>You are signed In </p>
  )
     
};

useAuth is a custom hook that provides session object and it uses react-query

export function useAuth(refreshInterval?: number) {
  const { error, data } = useQuery("sessionURL", fetchSession, {
    refetchOnWindowFocus: true,
    refetchOnMount: true,
    refetchOnReconnect: true,
    refetchInterval: refreshInterval || 25000,
  });

  return {
    session: data,
    loading: typeof data === "undefined" && typeof error === "undefined",
  };
}

_app.tsx

import type { AppProps } from "next/app";
import { SessionProvider } from "next-auth/react";
import { QueryClient, QueryClientProvider } from "react-query";

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
  const queryClient = new QueryClient();

  return (
    <QueryClientProvider client={queryClient}>
      <SessionProvider session={session}>
        <Component {...pageProps} />
      </SessionProvider>
    </QueryClientProvider>
  );
}

Using this approach, I have to define Unauthenticated route in every component. I want to define it Globally in _app.tsx like following

import { SessionProvider } from "next-auth/react";
import { QueryClient, QueryClientProvider } from "react-query";
import { useAuth } from "../utils/Hooks";

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
  const queryClient = new QueryClient();

  const { session, loading } = useAuth();

  if (!session) {
    return <UnAuthenticated />
  }

  return (
    <QueryClientProvider client={queryClient}>
      <SessionProvider session={session}>
        <Component {...pageProps} />
      </SessionProvider>
    </QueryClientProvider>
  );
}

export default MyApp;

BUT the problem is useAuth is using useQuery within it and it gives wrapping-error which is legit.

How can I make it work, is there any way I can define authentication globally ???

CodePudding user response:

So I think for this you should create a wrapper component that does the check on it's own and then renders out stuff so that you don't need to repeat it for each page.

// AuthWrapper.tsx

import UnAuthenticated from "./UnAuthenticated";
import useAuth from "../hooks/useAuth";
import { PropsWithChildren } from "react";

const AuthWrapper = ({ children }: PropsWithChildren<{}>) => {
  const { session, loading } = useAuth();

  if (!session) {
    return <UnAuthenticated />;
  }

  return <>{children}</>;
};

export default AuthWrapper;

And then use it in _app.tsx like so (Thanks to @Janik) And you can even prevent some pages to have authentication by using this little trick

import { SessionProvider } from "next-auth/react";
import { QueryClient, QueryClientProvider } from "react-query";
import { useAuth } from "../utils/Hooks";
import { useRouter } from "next/router";
import AuthWrapper from "../components/AuthProvider";

// Pages that don't require auth
const publicPages = ["/sign-in", "/sign-up"]; // or more if you want

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
  const queryClient = new QueryClient();
  const router = useRouter();

  const isPublicPage = publicPages.includes(router.pathname);

  return (
    <QueryClientProvider client={queryClient}>
      <SessionProvider session={session}>
        {isPublicPage ? (
          <Component {...pageProps} />
        ) : (
          <AuthWrapper>
            <Component {...pageProps} />
          </AuthWrapper>
        )}
      </SessionProvider>
    </QueryClientProvider>
  );
}

export default MyApp;
  • Related