'Session cookie exceeds allowed 4096 bytes.'-getting this Next Auth error after upgrading nextJs 14.1.4 from 14.1.0

74 Views Asked by At

I am using nextJs as frontend and express as backend. for authentication , I am using Next-Auth.

It was still fine when I upgraded nextJs 14.1.0 from 13.5 but yesterday I updated my next app into latest till now (v14.1.4) and I was getting a auth api error. Then again, I reverted into the previous version (14.1.0) and got the error solved. But got a new error while trying to log in.

In console, I am getting this: next auth error

The issue is, too many Next-auth session cookies is being set (here 7) to session storage. error

here's my authoptions:

import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { AuthOptions } from "next-auth";
import prisma from '@/libs/prismadb';
import bcrypt from "bcrypt";
import  CredentialsProvider  from 'next-auth/providers/credentials';

export const authOptions:AuthOptions = {
    adapter: PrismaAdapter(prisma),
    providers: [
        CredentialsProvider({
            name: 'credentials',
            credentials:{
                email: { label: 'email', type: 'text' },
                password: { label: 'password', type: 'text'},
            },
            async authorize(credentials) {

                if (!credentials?.email || !credentials.password) {
                    throw new Error(`Invalid credentials`)
                }

                const user = await prisma.user.findUnique({
                    where: {
                        email: credentials.email
                    }
                });
                if (!user || !user.hashedPassword) {
                    throw new Error(`Invalid credentials`);
                }

                const isCorrectPassword = await bcrypt.compare(credentials.password, user.hashedPassword);

                if (!isCorrectPassword) {
                    throw new Error(`Incorrect password`)
                }

                return user;

            }
        })
    ],
    debug: process.env.NODE_ENV === 'development',
    session: {
        strategy: 'jwt'
    },
    secret: process.env.NEXTAUTH_SECRET
}

I my Next-Auth folder path is :

src/app/api/auth/[...nextauth]/route.ts

and the route.ts includes :

import NextAuth from 'next-auth/next';
import { authOptions } from '@/utils/authOptions';


const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

How may I solve the issue? Or is there any good resource to authenticate using my external express server?

I tried rebuilding the app and discard all the changes after upgrading my nextJs app into latest version.

1

There are 1 best solutions below

0
Ahmet Firat Keler On BEST ANSWER

One workaround is to use Callbacks

SHORT ANSWER: Save only what you need in your session to avoid this warning.

I share an example with you. There is no prisma adapter in this one but the logic would be similar, please take this as a reference.

In this example, the login endpoint response object includes

  • id
  • accessToken
  • refreshToken
  • idToken

When we consider the token sizes, it is perfectly normal to get this warning as a result. To overcome this issue, we save only what we need in our session. To do this, we add two callback methods like below.

callbacks: {
    async jwt({ token, user, account }) {
        // I advise you to log those variables here to see what you get
        if (account && user) {
            token.id = user.id
            token.accessToken = user.accessToken
            token.refreshToken = user.refreshToken

            // idToken may include some user information such as email, I leave this piece of code as an example to understand how we can extract information from it
            const decodedIdToken = JSON.parse(Buffer.from(user.idToken.split(".")[1], "base64").toString())

            if (decodedIdToken) {
                token.email = decodedIdToken["email"]
            }
        }

        const { refreshToken, ...rest } = token // we do not return refreshToken here because it would increase the session cookie size
        return rest
    },
    async session({ session, token }) {
        return {
            ...session,
            user: {
                ...session.user,
                id: token.id as string,
                email: token.email as string,
                accessToken: token.accessToken as string,
            },
            error: "" // long story, I will not go into the details about this now
        }
    }
}

Reference: https://authjs.dev/guides/basics/callbacks

Of course, to prevent typescript complains, we need to add next-auth.d.ts file under the path /types (types folder is at the root of the project)

import { DefaultSession } from "next-auth"

declare module "next-auth" {
    interface User {
        id: string
        email: string
        accessToken: string
        refreshToken: string
        idToken: string
    }

    interface Session {
        user: User & DefaultSession["user"]
        expires: string
        error: string
    }
}

Reference: https://authjs.dev/getting-started/typescript

As you see, we can extract whatever info we need. We excluded refreshToken from the session cookie in this example. Someone may ask "So how can I access my refreshToken once my accessToken expired? We do not have it in the session". The answer is using cookies

After a successful login, we can save our refreshToken as an http only cookie

async authorize(credentials) {
    const payload = {
        email: credentials.email,
        password: credentials.password,
    }
    const res = await fetch(`${process.env.API_BASE_URL}/auth/login`, {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*",
        },
        body: JSON.stringify(payload)
    })

    const user = await res.json()

    if (!res.ok) {
        throw new Error(user.message)
    }

    if (res.ok && user) {
        cookies().set({
            name: `refresh-token`,
            value: user.refreshToken,
            httpOnly: true,
            sameSite: "strict",
            secure: true,
        } as any)

        return user
    }
    
    return null
}