From 3362c987815431420a6cc14646ff7726d0c9b4d6 Mon Sep 17 00:00:00 2001 From: PxlLoewe <72106766+PxlLoewe@users.noreply.github.com> Date: Tue, 11 Mar 2025 20:07:53 -0700 Subject: [PATCH] Fixed login bug when one app users the jwt of the other --- apps/dispatch/.env.example | 3 +- .../app/(auth)/login/_components/Login.tsx | 116 ++++++++------- .../app/api/auth/[...nextauth]/auth.ts | 134 ++++++++++-------- 3 files changed, 137 insertions(+), 116 deletions(-) diff --git a/apps/dispatch/.env.example b/apps/dispatch/.env.example index 07d01925..92ef77c0 100644 --- a/apps/dispatch/.env.example +++ b/apps/dispatch/.env.example @@ -1,2 +1,3 @@ NEXT_PUBLIC_HUB_URL= -NEXT_PUBLIC_SERVICE_ID= \ No newline at end of file +NEXT_PUBLIC_SERVICE_ID= +NEXTAUTH_SECRET= \ No newline at end of file diff --git a/apps/dispatch/app/(auth)/login/_components/Login.tsx b/apps/dispatch/app/(auth)/login/_components/Login.tsx index 76e5c388..0e9be153 100644 --- a/apps/dispatch/app/(auth)/login/_components/Login.tsx +++ b/apps/dispatch/app/(auth)/login/_components/Login.tsx @@ -1,60 +1,68 @@ -'use client'; -import { signIn } from 'next-auth/react'; -import { useSearchParams } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { Toaster } from 'react-hot-toast'; +"use client"; +import { signIn, useSession } from "next-auth/react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import { Toaster } from "react-hot-toast"; export const Login = () => { - const [isLoading, setIsLoading] = useState(false); - const searchParams = useSearchParams(); + const [isLoading, setIsLoading] = useState(false); + const searchParams = useSearchParams(); + const { data: session } = useSession(); + const navigate = useRouter(); - useEffect(() => { - const signInWithCode = async () => { - const code = searchParams.get('code'); - if (code) { - setIsLoading(true); - await signIn('credentials', { - code: code, - callbackUrl: '/', - }); - setIsLoading(false); - } - }; - signInWithCode(); - }, [searchParams]); + useEffect(() => { + if (session) { + navigate.push("/"); + } + }, [session, navigate]); - return ( -
-
- -
-

Login

- - Noch keinen Account? Zur{' '} - - Registrierung - - + useEffect(() => { + const signInWithCode = async () => { + const code = searchParams.get("code"); + if (code) { + setIsLoading(true); + await signIn("credentials", { + code: code, + callbackUrl: "/", + }); + setIsLoading(false); + } + }; + signInWithCode(); + }, [searchParams]); -
- - - -
-
- ); + return ( +
+
+ +
+

Login

+ + Noch keinen Account? Zur{" "} + + Registrierung + + + +
+ + + +
+
+ ); }; diff --git a/apps/dispatch/app/api/auth/[...nextauth]/auth.ts b/apps/dispatch/app/api/auth/[...nextauth]/auth.ts index 17636942..79259789 100644 --- a/apps/dispatch/app/api/auth/[...nextauth]/auth.ts +++ b/apps/dispatch/app/api/auth/[...nextauth]/auth.ts @@ -1,70 +1,82 @@ import { - AuthOptions, - getServerSession as getNextAuthServerSession, -} from 'next-auth'; -import { PrismaAdapter } from '@next-auth/prisma-adapter'; -import Credentials from 'next-auth/providers/credentials'; -import { PrismaClient } from '@repo/db'; -const prisma = new PrismaClient(); + AuthOptions, + getServerSession as getNextAuthServerSession, +} from "next-auth"; +import { PrismaAdapter } from "@next-auth/prisma-adapter"; +import Credentials from "next-auth/providers/credentials"; +import { prisma, PrismaClient } from "@repo/db"; export const options: AuthOptions = { - providers: [ - Credentials({ - credentials: { - code: { label: 'code', type: 'code' }, - }, - async authorize(credentials, req) { - try { - if (!credentials) throw new Error('No credentials provided'); - const code = await prisma.oAuthToken.findFirstOrThrow({ - where: { - accessToken: credentials.code, - }, - }); - const user = await prisma.user.findFirstOrThrow({ - where: { - id: code.userId, - }, - }); + providers: [ + Credentials({ + credentials: { + code: { label: "code", type: "code" }, + }, + async authorize(credentials, req) { + try { + if (!credentials) throw new Error("No credentials provided"); + const code = await prisma.oAuthToken.findFirstOrThrow({ + where: { + accessToken: credentials.code, + }, + }); + const user = await prisma.user.findFirstOrThrow({ + where: { + id: code.userId, + }, + }); - if (!user) return null; + if (!user) return null; - return user; - } catch (error) { - return null; - } - }, - }), - ], - secret: process.env.NEXTAUTH_SECRET, - session: { - strategy: 'jwt', - maxAge: 30 * 24 * 60 * 60, - }, + return user; + } catch (error) { + console.error(error); + return null; + } + }, + }), + ], + secret: process.env.NEXTAUTH_SECRET, + cookies: { + sessionToken: { + name: `next-auth.session-token-${process.env.NEXTAUTH_URL}`, + options: { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "lax", + path: "/", + }, + }, + }, - adapter: PrismaAdapter(prisma as any), - callbacks: { - jwt: async ({ token, user }) => { - if (user && 'firstname' in user) { - return { - ...token, - ...user, - }; - } - return token; - }, - session: async ({ session, user, token }) => { - return { - ...session, - user: token, - }; - }, - }, - pages: { - signIn: '/login', - signOut: '/logout', - error: '/authError', - }, + session: { + strategy: "jwt", + maxAge: 30 * 24 * 60 * 60, + }, + + adapter: PrismaAdapter(prisma as any), + callbacks: { + jwt: async ({ token, user }) => { + if (user && "firstname" in user) { + return { + ...token, + ...user, + }; + } + return token; + }, + session: async ({ session, user, token }) => { + return { + ...session, + user: token, + }; + }, + }, + pages: { + signIn: "/login", + signOut: "/logout", + error: "/authError", + }, } satisfies AuthOptions; export const getServerSession = async () => getNextAuthServerSession(options);