From 2723fdc3904d2f390d79625478ab4903b86e9880 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Thu, 8 Feb 2024 14:07:09 +0100 Subject: [PATCH 1/2] ar(fix) fixes server side csrf login --- lib/auth/constants.ts | 16 ++++--- src/app/api/auth/[...nextauth]/route.ts | 1 - src/app/components/client/signup-view.tsx | 1 + src/app/error/page.tsx | 52 +++++++++++++++++++++++ src/app/signin/page.tsx | 12 +++++- src/app/verify/page.tsx | 52 +++++++++++++++++++++++ 6 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 src/app/error/page.tsx create mode 100644 src/app/verify/page.tsx diff --git a/lib/auth/constants.ts b/lib/auth/constants.ts index 840a0cb2..2d31f11f 100644 --- a/lib/auth/constants.ts +++ b/lib/auth/constants.ts @@ -39,9 +39,15 @@ export const authOptions: AuthOptions = { }, }, callbacks: { - // async signIn() { - - // }, + async signIn({ user, account, profile, email, credentials }) { + // extra sign-in checks + return true + }, + async redirect ({url, baseUrl}) { + return url.startsWith(baseUrl) + ? Promise.resolve(url) + : Promise.resolve(baseUrl) + }, async jwt({ user, token }) { if (user) { // Note that this if condition is needed @@ -60,8 +66,8 @@ export const authOptions: AuthOptions = { pages: { signIn: '/signin', signOut: '/', - // error: '/api/rm/v0/auth/error', // Error code passed in query string as ?error= - // verifyRequest: '/api/rm/v0/auth/verify-request', // (used for check email message) + error: '/error', // Error code passed in query string as ?error= + verifyRequest: '/verify', // (used for check email message) // newUser: '/' // New users will be directed here on first sign in (leave the property out if not of interest) }, }; diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts index 513940c3..a80e93db 100644 --- a/src/app/api/auth/[...nextauth]/route.ts +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -1,5 +1,4 @@ // api/auth/route.ts simple poc - // [...nextauth].ts// auth.ts TS-Doc? import NextAuth from 'next-auth'; import { finalAuth } from '@auth/adapter'; diff --git a/src/app/components/client/signup-view.tsx b/src/app/components/client/signup-view.tsx index e89b4f09..cc1174ec 100644 --- a/src/app/components/client/signup-view.tsx +++ b/src/app/components/client/signup-view.tsx @@ -91,6 +91,7 @@ export const VSignUp = ({ providers, user, csrf }: VSignUpProps) => {
+ { + const session = await getServerSession(authOptions); + + // If the user is already logged in, redirect. + // Note: Make sure not to redirect to the same page + // To avoid an infinite loop! + if (session) { + return redirect(process.env.NEXUS_BASE_PATH || '/'); + } + + const providers = (await getProviders()) as unknown as IAuthProviders[]; + + return { providers: providers ?? [] }; +} + +export default async function SignUp() { + const props: ISignInData = await getProvidersData(); + const providers: IAuthProviders[] = props?.providers || []; + cookies(); + const csrf: string | undefined = await getCsrfToken(); + return ( +
+
+ +

There was an error logging you in.

+

Please be patient, this is still an Alpha release and not official.

+
+
+ ); +} diff --git a/src/app/signin/page.tsx b/src/app/signin/page.tsx index 2bb2f531..4686768e 100644 --- a/src/app/signin/page.tsx +++ b/src/app/signin/page.tsx @@ -38,8 +38,16 @@ async function getProvidersData(): Promise { export default async function SignUp() { const props: ISignInData = await getProvidersData(); const providers: IAuthProviders[] = props?.providers || []; - cookies(); - const csrf: string | undefined = await getCsrfToken(); + const cook = cookies(); + const cookieCsrf: string | undefined = await getCsrfToken({ + req: { + headers: { + cookie: cookies().toString(), + }, + }, + }); + const newCsrf: string | undefined = await getCsrfToken(); + const csrf = cookieCsrf || newCsrf return (
diff --git a/src/app/verify/page.tsx b/src/app/verify/page.tsx new file mode 100644 index 00000000..faebffc9 --- /dev/null +++ b/src/app/verify/page.tsx @@ -0,0 +1,52 @@ +// signin/page.tsx TS-Doc? +'use server'; +import { getProviders, getCsrfToken } from 'next-auth/react'; +import { getServerSession } from 'next-auth/next'; +import { redirect } from 'next/navigation'; +import { cookies } from 'next/headers'; +import { authOptions } from '@auth'; +import { VSignUp } from '@components/client'; +import styles from '@styles/page.module.css'; + +interface ISignInData { + providers?: IAuthProviders[]; + redirect?: { + destination?: string; + }; +} + +interface IAuthProviders { + id?: string; + name?: string; +} + +async function getProvidersData(): Promise { + const session = await getServerSession(authOptions); + + // If the user is already logged in, redirect. + // Note: Make sure not to redirect to the same page + // To avoid an infinite loop! + if (session) { + return redirect(process.env.NEXUS_BASE_PATH || '/'); + } + + const providers = (await getProviders()) as unknown as IAuthProviders[]; + + return { providers: providers ?? [] }; +} + +export default async function SignUp() { + const props: ISignInData = await getProvidersData(); + const providers: IAuthProviders[] = props?.providers || []; + cookies(); + const csrf: string | undefined = await getCsrfToken(); + return ( +
+
+ +

Please check your email.

+

There should be a login link there.

+
+
+ ); +} From 12674762d0c8978b648dc74921ecf4b83d602ef8 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Thu, 8 Feb 2024 14:12:36 +0100 Subject: [PATCH 2/2] ar(lint) --- lib/auth/constants.ts | 10 ++++------ src/app/error/page.tsx | 37 ------------------------------------- src/app/signin/page.tsx | 4 ++-- src/app/verify/page.tsx | 37 ------------------------------------- 4 files changed, 6 insertions(+), 82 deletions(-) diff --git a/lib/auth/constants.ts b/lib/auth/constants.ts index 2d31f11f..362344e5 100644 --- a/lib/auth/constants.ts +++ b/lib/auth/constants.ts @@ -39,14 +39,12 @@ export const authOptions: AuthOptions = { }, }, callbacks: { - async signIn({ user, account, profile, email, credentials }) { + async signIn() { // extra sign-in checks - return true + return true; }, - async redirect ({url, baseUrl}) { - return url.startsWith(baseUrl) - ? Promise.resolve(url) - : Promise.resolve(baseUrl) + async redirect({ url, baseUrl }) { + return url.startsWith(baseUrl) ? Promise.resolve(url) : Promise.resolve(baseUrl); }, async jwt({ user, token }) { if (user) { diff --git a/src/app/error/page.tsx b/src/app/error/page.tsx index 4a8c89f8..f12ea2e5 100644 --- a/src/app/error/page.tsx +++ b/src/app/error/page.tsx @@ -1,45 +1,8 @@ // signin/page.tsx TS-Doc? 'use server'; -import { getProviders, getCsrfToken } from 'next-auth/react'; -import { getServerSession } from 'next-auth/next'; -import { redirect } from 'next/navigation'; -import { cookies } from 'next/headers'; -import { authOptions } from '@auth'; -import { VSignUp } from '@components/client'; import styles from '@styles/page.module.css'; -interface ISignInData { - providers?: IAuthProviders[]; - redirect?: { - destination?: string; - }; -} - -interface IAuthProviders { - id?: string; - name?: string; -} - -async function getProvidersData(): Promise { - const session = await getServerSession(authOptions); - - // If the user is already logged in, redirect. - // Note: Make sure not to redirect to the same page - // To avoid an infinite loop! - if (session) { - return redirect(process.env.NEXUS_BASE_PATH || '/'); - } - - const providers = (await getProviders()) as unknown as IAuthProviders[]; - - return { providers: providers ?? [] }; -} - export default async function SignUp() { - const props: ISignInData = await getProvidersData(); - const providers: IAuthProviders[] = props?.providers || []; - cookies(); - const csrf: string | undefined = await getCsrfToken(); return (
diff --git a/src/app/signin/page.tsx b/src/app/signin/page.tsx index 4686768e..9865d384 100644 --- a/src/app/signin/page.tsx +++ b/src/app/signin/page.tsx @@ -42,12 +42,12 @@ export default async function SignUp() { const cookieCsrf: string | undefined = await getCsrfToken({ req: { headers: { - cookie: cookies().toString(), + cookie: cook.toString(), }, }, }); const newCsrf: string | undefined = await getCsrfToken(); - const csrf = cookieCsrf || newCsrf + const csrf = cookieCsrf || newCsrf; return (
diff --git a/src/app/verify/page.tsx b/src/app/verify/page.tsx index faebffc9..2621ce95 100644 --- a/src/app/verify/page.tsx +++ b/src/app/verify/page.tsx @@ -1,45 +1,8 @@ // signin/page.tsx TS-Doc? 'use server'; -import { getProviders, getCsrfToken } from 'next-auth/react'; -import { getServerSession } from 'next-auth/next'; -import { redirect } from 'next/navigation'; -import { cookies } from 'next/headers'; -import { authOptions } from '@auth'; -import { VSignUp } from '@components/client'; import styles from '@styles/page.module.css'; -interface ISignInData { - providers?: IAuthProviders[]; - redirect?: { - destination?: string; - }; -} - -interface IAuthProviders { - id?: string; - name?: string; -} - -async function getProvidersData(): Promise { - const session = await getServerSession(authOptions); - - // If the user is already logged in, redirect. - // Note: Make sure not to redirect to the same page - // To avoid an infinite loop! - if (session) { - return redirect(process.env.NEXUS_BASE_PATH || '/'); - } - - const providers = (await getProviders()) as unknown as IAuthProviders[]; - - return { providers: providers ?? [] }; -} - export default async function SignUp() { - const props: ISignInData = await getProvidersData(); - const providers: IAuthProviders[] = props?.providers || []; - cookies(); - const csrf: string | undefined = await getCsrfToken(); return (