From ed2beb1b632eab45c07a5709f0a9777f82ab857e Mon Sep 17 00:00:00 2001 From: Ikram Bagban <107988060+IkramBagban@users.noreply.github.com> Date: Sat, 7 Dec 2024 02:00:44 +0530 Subject: [PATCH] fix: multiple login session bug #1517 (#1520) * fix: Enforce single-session login by invalidating previous JWTs on new login #1517 * Update src/middleware.ts --------- Co-authored-by: Sargam --- src/lib/auth.ts | 8 ++++++-- src/middleware.ts | 20 +++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 4b09a6a68..9f52f422a 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -6,6 +6,7 @@ import prisma from '@/db'; import { NextAuthOptions } from 'next-auth'; import { Session } from 'next-auth'; import { JWT } from 'next-auth/jwt'; +import { randomUUID } from 'crypto'; interface AppxSigninResponse { data: { @@ -43,9 +44,12 @@ const generateJWT = async (payload: JWTPayload) => { const jwk = await importJWK({ k: secret, alg: 'HS256', kty: 'oct' }); - const jwt = await new SignJWT(payload) + const jwt = await new SignJWT({ + ...payload, + iat: Math.floor(Date.now() / 1000), + jti: randomUUID(), // Adding a unique jti to ensure each token is unique. This helps generate a unique jwtToken on every login + }) .setProtectedHeader({ alg: 'HS256' }) - .setIssuedAt() .setExpirationTime('365d') .sign(jwk); diff --git a/src/middleware.ts b/src/middleware.ts index c7feccfa9..4f6585a11 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,9 +1,10 @@ -import { NextRequestWithAuth, withAuth } from 'next-auth/middleware'; +import { NextRequestWithAuth } from 'next-auth/middleware'; import { NextResponse, NextRequest } from 'next/server'; import { jwtVerify, importJWK, JWTPayload } from 'jose'; +import { getToken } from 'next-auth/jwt'; export const config = { - matcher: ['/courses/:path*', '/api/mobile/:path*'], + matcher: ['/courses/:path*', '/api/mobile/:path*', '/home'], }; interface RequestWithUser extends NextRequest { @@ -55,12 +56,15 @@ export const withMobileAuth = async (req: RequestWithUser) => { }); }; -export default withAuth(async (req) => { +const withAuth = async (req: NextRequestWithAuth) => { if (process.env.LOCAL_CMS_PROVIDER) return; - const token = req.nextauth.token; + + const token = await getToken({ req }); + if (!token) { return NextResponse.redirect(new URL('/invalidsession', req.url)); } + const user = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL_LOCAL}/api/user?token=${token.jwtToken}`, ); @@ -69,12 +73,14 @@ export default withAuth(async (req) => { if (!json.user) { return NextResponse.redirect(new URL('/invalidsession', req.url)); } -}); +}; -export function middleware(req: NextRequestWithAuth) { +export async function middleware(req: NextRequestWithAuth) { const { pathname } = req.nextUrl; if (pathname.startsWith('/api/mobile')) { return withMobileAuth(req); } - return withAuth(req); + return await withAuth(req); } + +export default withAuth;