From 7217e23b1bf918046ccbb5db8ecb1ff084f8cfb5 Mon Sep 17 00:00:00 2001 From: atrincas Date: Tue, 7 Jan 2025 09:28:39 +0100 Subject: [PATCH] refactor: improve auth handling and route protection --- client/src/hoc/auth.ts | 29 ++++++++++++++----- client/src/pages/api/auth/[...nextauth].ts | 13 ++++++++- .../auth/change-password/[token]/index.tsx | 4 +++ client/src/pages/auth/forgot-password.tsx | 3 ++ client/src/pages/auth/signin.tsx | 20 ++----------- .../src/pages/auth/signup/[token]/index.tsx | 4 +++ client/src/pages/protected-example.tsx | 0 7 files changed, 47 insertions(+), 26 deletions(-) delete mode 100644 client/src/pages/protected-example.tsx diff --git a/client/src/hoc/auth.ts b/client/src/hoc/auth.ts index 1e982f60..3ae9a0c3 100644 --- a/client/src/hoc/auth.ts +++ b/client/src/hoc/auth.ts @@ -1,13 +1,14 @@ import { GetServerSideProps, GetServerSidePropsContext } from 'next'; -import { getServerSession } from 'next-auth/next'; -import { authOptions } from 'pages/api/auth/[...nextauth]'; +import { auth } from 'pages/api/auth/[...nextauth]'; -export function withAuth(gssp: GetServerSideProps) { +export function withAuth(gssp?: GetServerSideProps) { return async (context: GetServerSidePropsContext) => { - const session = await getServerSession(context.req, context.res, authOptions); + const session = await auth(context.req, context.res); + const isPublicRoute = context.req.url?.includes('/auth/'); - if (!session) { + if (!session && !isPublicRoute) { + // Protected route without session -> redirect to signin return { redirect: { destination: '/auth/signin', @@ -16,10 +17,24 @@ export function withAuth(gssp: GetServerSideProps) { }; } - const gsspData = await gssp(context); + if (session && isPublicRoute) { + // Public route (auth pages) with session -> redirect to projects + return { + redirect: { + destination: '/projects', + permanent: false, + }, + }; + } + + if (gssp) { + const gsspData = await gssp(context); + + return gsspData; + } return { - ...gsspData, + props: {}, }; }; } diff --git a/client/src/pages/api/auth/[...nextauth].ts b/client/src/pages/api/auth/[...nextauth].ts index 75921f87..c32074ff 100644 --- a/client/src/pages/api/auth/[...nextauth].ts +++ b/client/src/pages/api/auth/[...nextauth].ts @@ -1,5 +1,7 @@ import axios from 'axios'; -import NextAuth from 'next-auth'; +import { NextApiRequest, NextApiResponse } from 'next'; +import { GetServerSidePropsContext } from 'next'; +import NextAuth, { getServerSession } from 'next-auth'; import type { NextAuthOptions } from 'next-auth'; // eslint-disable-next-line @typescript-eslint/no-unused-vars import { JWT } from 'next-auth/jwt'; @@ -74,4 +76,13 @@ export const authOptions: NextAuthOptions = { }, }; +export function auth( + ...args: + | [GetServerSidePropsContext['req'], GetServerSidePropsContext['res']] + | [NextApiRequest, NextApiResponse] + | [] +) { + return getServerSession(...args, authOptions); +} + export default NextAuth(authOptions); diff --git a/client/src/pages/auth/change-password/[token]/index.tsx b/client/src/pages/auth/change-password/[token]/index.tsx index d2c914f1..781b2d71 100644 --- a/client/src/pages/auth/change-password/[token]/index.tsx +++ b/client/src/pages/auth/change-password/[token]/index.tsx @@ -2,10 +2,14 @@ import { useParams } from 'next/navigation'; import ChangePassword from 'containers/auth/change-password'; +import { withAuth } from 'hoc/auth'; + const ChangePasswordPage = () => { const params = useParams<{ token: string } | null>(); return ; }; +export const getServerSideProps = withAuth(); + export default ChangePasswordPage; diff --git a/client/src/pages/auth/forgot-password.tsx b/client/src/pages/auth/forgot-password.tsx index 420b7ad9..330dd75d 100644 --- a/client/src/pages/auth/forgot-password.tsx +++ b/client/src/pages/auth/forgot-password.tsx @@ -9,6 +9,7 @@ import { AuthWrapper } from 'containers/wrapper/component'; import Button from 'components/button'; import LinkButton from 'components/button/component'; import { Input } from 'components/forms'; +import { withAuth } from 'hoc/auth'; import authenticationService from 'services/authentication'; @@ -76,4 +77,6 @@ const ForgotPasswordPage = () => { ); }; +export const getServerSideProps = withAuth(); + export default ForgotPasswordPage; diff --git a/client/src/pages/auth/signin.tsx b/client/src/pages/auth/signin.tsx index 1339379b..963c099f 100644 --- a/client/src/pages/auth/signin.tsx +++ b/client/src/pages/auth/signin.tsx @@ -6,14 +6,13 @@ import Link from 'next/link'; import { useRouter } from 'next/router'; import { FORM_ERROR } from 'final-form'; -import { getServerSession } from 'next-auth/next'; import { signIn } from 'next-auth/react'; import { AuthWrapper } from 'containers/wrapper/component'; import Button from 'components/button'; import { Input } from 'components/forms/input/component'; -import { authOptions } from 'pages/api/auth/[...nextauth]'; +import { withAuth } from 'hoc/auth'; const SignInPage: React.FC = () => { const router = useRouter(); @@ -86,21 +85,6 @@ const SignInPage: React.FC = () => { ); }; -export async function getServerSideProps(context) { - const session = await getServerSession(context.req, context.res, authOptions); - - if (session) { - return { - redirect: { - destination: '/projects', - permanent: false, - }, - }; - } - - return { - props: {}, - }; -} +export const getServerSideProps = withAuth(); export default SignInPage; diff --git a/client/src/pages/auth/signup/[token]/index.tsx b/client/src/pages/auth/signup/[token]/index.tsx index faf758dd..c8c70de8 100644 --- a/client/src/pages/auth/signup/[token]/index.tsx +++ b/client/src/pages/auth/signup/[token]/index.tsx @@ -2,10 +2,14 @@ import { useParams } from 'next/navigation'; import ChangePassword from 'containers/auth/change-password'; +import { withAuth } from 'hoc/auth'; + const SignupPage = () => { const params = useParams<{ token: string } | null>(); return ; }; +export const getServerSideProps = withAuth(); + export default SignupPage; diff --git a/client/src/pages/protected-example.tsx b/client/src/pages/protected-example.tsx deleted file mode 100644 index e69de29b..00000000