Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 339
MateuszWawrzynski Avatar asked Oct 28 '20 16:10

MateuszWawrzynski


1 Answers

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
    }
}
...
like image 188
MateuszWawrzynski Avatar answered Nov 03 '22 23:11

MateuszWawrzynski