Where and how to change session user object after signing in?

11,597

I resolved that problem by myself.
This issue thread helped me a lot!
https://github.com/nextauthjs/next-auth/issues/764

Below is the explanation:

callbacks: {
    jwt: async (token, user, account, profile, isNewUser) => {
        //  "user" parameter is the object received from "authorize"
        //  "token" is being send below to "session" callback...
        //  ...so we set "user" param of "token" to object from "authorize"...
        //  ...and return it...
        user && (token.user = user);
        return Promise.resolve(token)   // ...here
    },
    session: async (session, user, sessionToken) => {
        //  "session" is current session object
        //  below we set "user" param of "session" to value received from "jwt" callback
        session.user = user.user;
        return Promise.resolve(session)
    }
}

EDIT: Due to NextAuth update to v4

Version 4 of NextAuth brings some changes to callbacks shown above. Now there is only one argument assigned to jwt and session functions. However, you can destructure it to separate variables. Rest of the code stays the same as before.

https://next-auth.js.org/configuration/callbacks#jwt-callback
https://next-auth.js.org/configuration/callbacks#session-callback

// api/auth/[...nextauth].js

...
callbacks: {
    jwt: async ({ token, user }) => {
        user && (token.user = user)
        return token
    },
    session: async ({ session, token }) => {
        session.user = token.user
        return session
    }
}
...
Share:
11,597
MateuszWawrzynski
Author by

MateuszWawrzynski

Hello World!

Updated on July 09, 2022

Comments

  • MateuszWawrzynski
    MateuszWawrzynski almost 2 years

    I have weird problem and I don't know where the problem is. I use next-auth library to make authentication system in my Next.js app.

    Everything is OK - I can sign in by checking if there is account in google firebase with submitted credentials, session is being created properly, but when the authorize callback is initialized I pass data received from google firestore after correct sign in. User object contains whole data and it's passed forward.

    Then, when I want to read data from session, some data I passed before is missing.

    Code:

    /pages/api/auth/[...nextauth.js]

    export default (req, res) => 
        NextAuth(req, res, {
            providers: [
                Providers.Credentials({
                    name: 'Credentials',
                    credentials: {
                        phone: { label: "Phone number", type: "text" },
                        password: { label: "Password", type: "password" }
                    },
                    authorize: async (loginData) => {
                        const { csrfToken, phone, password } = loginData;
                        
                        //  checking if there is account with these credentials
                        let res = await login({
                            phone, 
                            password: sha1(md5(password)).toString()
                        })
    
                        //  200 = OK
                        if(res.status == 200){
                            //  collect account data
                            const user = {
                                phone,
                                ...res.data.info
                            }
    
                            //  user object is created correctly, whole data is stored there
                            console.log('received account data from firestore', user)
                            return Promise.resolve(user);
                        }
                        else {
                            //  wrong credentials
                            return Promise.resolve(null);
                        }
                    }
                })
            ],
            callbacks: {
                session: async (session, user) => {
                    console.log('data passed to object when signed in', user)
                    //  user object there doesn't have all data passed before
                    return Promise.resolve(session)
                }
            },
            debug: false
        })
    

    Console logged objects:

    received account data from firestore 
    {
      phone: '123123123',
      id: 'w2zh88BZzSv5BJeXZeZX',
      email: '[email protected]',
      name: 'Jan',
      surname: 'Kowalski'
    }
    
    data passed to object when signed in 
    {
      name: 'Jan',
      email: '[email protected]',
      iat: 1603900133,
      exp: 1606492133
    }
    

    The best thing is, the object (above) always has the same properties. I can pass any object in authorize callback, but in session, user object always has "name, email, iat, exp" ALWAYS. The only thing that changes are values of these two properties in object (name, email). (rest properties - "phone, id, surname" - are missing).

    Below there is console logged session object in any react component:

    import {
        signIn, 
        signOut,
        useSession
    } from 'next-auth/client'
    
    const [ session, loading ] = useSession();
    console.log(session)
    

    Photo of console logged session object

    What can I do? Do I have to receive data from firestore separately in session callback? Is the server-side rendering of Next.js causing the problem?

  • entithat
    entithat over 3 years
    You saved my life :)
  • ABCD.ca
    ABCD.ca over 3 years
    Thanks, this was a good lead. These days the signature looks more like, session: async (session, user) => {. Also, since you're using async you can just return session, you don't need to use Promise.resolve.
  • Richard Vartan Melkonian
    Richard Vartan Melkonian over 2 years
    this solved my issue too, thanks for the edit for v4.
  • Chayanin
    Chayanin almost 2 years
    The property to be attached to token and session objects has to be "user" only. I wasted a lot of time trying to name it something else. Finally made it works with this answer. Thanks!