nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
24.41k stars 3.42k forks source link

Unexpected Modification of User Object in Next.js Authentication Callback #10593

Open loki4514 opened 5 months ago

loki4514 commented 5 months ago

Environment

I'm facing an issue with user authentication in a Next.js application using NextAuth. I have implemented a custom signIn callback for Google OAuth authentication, where I check if the user exists in the database and return it if found. However, I'm encountering unexpected behavior where the user object seems to be modified or overwritten.

Example in Database i have already have record name : ijk email : abc@gmail.com

when i use google login, name : abc email : abc@gmail.com

since the email already exists it should return {name: ikj, email: abc@gmail.com} instead it returns {name : abc, email : abc@gmail.com}, which is an unexpected behaviour. {name : abc, email : abc@gmail.com} this getting stored in authprovider and in backend returns the status code of 401

async signIn is the main fucntion of google outh

Reproduction URL

https://github.com/loki4514/Blog-App

Describe the issue

export const authOptions: NextAuthOptions = {
    providers: [
        CredentialsProvider({
            name: "crendentials",
            credentials: {},
            async authorize(credentials, req): Promise<any> {
                const { email, password } = credentials as {
                    email: string;
                    password: string;
                };
                try {
                    const user = await User.findOne({ email })
                    if (!user) {
                        // Assuming you have access to the response object 'res'
                        return null
                    }

                    const comparedpassword: boolean = await bcryptjs.compare(password, user.password)
                    if (!comparedpassword) {
                        return null
                    }
                    return user;

                } catch (error: any) {
                    console.log("Error:", error)
                    return null
                }
            }

        }),
        GoogleProvider({
            clientId: GOOGLE_CLIENT_ID! as string,
            clientSecret: GOOGLE_CLIENT_SECRET! as string
        })
    ],

    session: {
        strategy: 'jwt'
    },

    callbacks: {

        async signIn({ user, account }: { user: any; account: any }) {
            if (account.provider === "google" && user) {
                try {

                    const { name, email }: { name: string; email: string } = user;
                    const existingUser = await User.findOne({ email });
                    if (existingUser) {
                        return existingUser; // Return existing user
                    }

                    const newUser = new User({
                        name: name,
                        email: email,
                        isVerified: true 
                    });

                    const savedUser = await newUser.save();

                    return savedUser; // Return the newly created user
                } catch (error) {
                    console.error("Error in Google OAuth signIn callback:", error);
                    return null; 
                }
            }
        else {
        // not hiting the else block
            console.log("why is i'm getting called here")
            return user;

        }

        },

        async jwt({ token, user }) {
            if (user) {
                console.log(user,"this failed in every aspect of my life 0001")
                // i should existingUser object but i'm not getting it
                token.email = user.email
                token.name = user.name
                token.id = user.id

            }
            if (!user) 
                token.error = "Invalid Credentials"
                token.errorStatus = 401; // Set error status code
            }
            return token
        },
        async session({ session, token }: { session: any, token: any }) {
            if (session.user) {
                session.user.email = token.email;
                session.user.name = token.name;
                session.user.id = token.id;

            }
            return session

        }
    },
    secret: process.env.NEXTAUTH_SECRET!,
    pages: {
        signIn: '/login'
    }

}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }`

How to reproduce

Currently i working in local repository

Expected behavior

Despite returning the existing user if found, the user object appears to be modified, causing inconsistencies in authentication. I've ensured that there are no explicit variable reassignments within the callback function.

I've tried debugging the issue, but I'm unable to identify the root cause. Could someone please help me understand why the user object is being modified unexpectedly and suggest how to resolve this issue?

Any insights or suggestions would be greatly appreciated. Thanks in advance!

here is stackoverflow question Link

JasperAlexander commented 5 months ago

You should retrieve the user in the jwt callback with token.email. Then you can use it to set the token entries.