nextauthjs / next-auth

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

NextAuth: Session Callback Not Triggered on Vercel (but Triggerred Fine on Localhost) #9081

Closed mtando closed 10 months ago

mtando commented 10 months ago

Environment

localhost

→ node --version v18.17.0

Apple M1 Pro Ventura 13.3.1

Chrome Version 119.0.6045.105 (Official Build) (arm64)

Vercel

Node 18.x

Reproduction URL

qa.tokogame.com

Describe the issue

On localhost, Google login always works perfectly fine. But upon deploying this to Vercel, session is always empty {} after successful Google login. I looked at the logs on Vercel and I can see that session callback was never executed on Vercel (only executed on localhost)

package.json: "dependencies": { "axios": "^0.21.1", "next": "^14.0.1", "next-auth": "4.24.4", "next-pwa": "^5.4.4", "next-seo": "^5.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-query": "^3.19.1", "styled-components": "^5.3.0", },

[...nextauth].js:

export const authOptions = { providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), ], secret: process.env.NEXTAUTH_SECRET, jwt: { secret: process.env.NEXTAUTH_SECRET, encryption: true, }, debug: true, session: { // Choose how you want to save the user session. // The default is"jwt", an encrypted JWT (JWE) stored in the session cookie. // If you use anadapterhowever, we default it to"database"instead. // You can still force a JWT session by explicitly defining"jwt". // When using"database", the session cookie will only contain asessionToken` value, // which is used to look up the session in the database. strategy: "jwt",

// Seconds - How long until an idle session expires and is no longer valid.
// 30 days.
// We need to handle if backend returns error which says that token has expired
// and then force logout user.
maxAge: 30 * 24 * 60 * 60,

// Seconds - Throttle how frequently to write to database to extend a session.
// Use it to limit write operations. Set to 0 to always update the database.
// Note: This option is ignored if using JSON Web Tokens
// updateAge: 24 * 60 * 60, // 24 hours

// The session token is usually either a random UUID or string, however if you
// need a more customized session token string, you can define your own generate function.
// generateSessionToken: () => {
//   return randomUUID?.() ?? randomBytes(32).toString("hex")
// }

},

callbacks: { async jwt({ token, user, account }) { // Persist the user.authToken from signIn callback to the token.authToken

  if (account) {
    // Handle the Google ID token here
    const googleIdToken = account.id_token;
    // console.log("nextauth.js jwt: got googleIdToken " + googleIdToken);
    // Send the Google ID token to our backend for verification
    // and exchange it for our backend's token
    // TODO: no way to get locale for now.
    const res = await reqGoogleTokenSignIn(null, googleIdToken);
    const member = res?.data?.data;
    if (member == null) {
      console.log(
        "nextauth.js jwt reqGoogleTokenSignIn: Failed response from be"
      );
      return false;
    }

    console.log(
      "nextauth.js jwt reqGoogleTokenSignIn: Received response from be. authToken: " +
        member.authToken
    );

    let newToken = {};
    newToken.userId = member.id;
    newToken.authToken = member.authToken;
    newToken.profilePictureUrl = member.profilePictureUrl;
    newToken.fullName = member.fullName;
    newToken.emailAddress = member.emailAddress;
    newToken.phoneNumber = member.phoneNumber;

    console.log("nextauth.js jwt: setting token's userId and authToken");
    return newToken;
  }

  return token;
},

async session({ session, token }) {
  // Persist the token.authToken from jwt callback to the session.authToken

  console.log(
    "nextauth.js session: setting session's userId and authToken"
  );
  session.userId = token?.userId;
  session.authToken = token?.authToken;
  session.profilePictureUrl = token?.profilePictureUrl;
  session.fullName = token?.fullName;
  session.emailAddress = token?.emailAddress;
  session.phoneNumber = token?.phoneNumber;

  return session;
},

}, }; export default NextAuth(authOptions);`

My component that uses session:

LoginBtn.js ` function LoginBtn({ provider }) { const { data: session, status } = useSession(); const [loggedIn, setLoggedIn] = useState(null);

let loginButton = (

signIn("google", { callbackUrl: "/members/profile" })} priority={true} src="/assets/google-login.png" alt={"Login with Google"} height={32} width={82} />

);

let profileButton = (

);

useEffect(() => { if (session == null && status === "loading") { return; } else if (session == null && status === "unauthenticated") { setLoggedIn(false); return; } else if (session != null && status === "authenticated") { setLoggedIn(true); return; } }, [session, status]);

return loggedIn == null ? null : loggedIn ? profileButton : loginButton; }

export default LoginBtn; `

From Vercel's log: i can see these 2 logs were printed:

nextauth.js jwt reqGoogleTokenSignIn: Received response from be. authToken: Lcoury0Lfl5MRHfRVs6GY280H144=

nextauth.js jwt: setting token's userId and authToken

but it's missing the log from session callback ("nextauth.js session: setting session's userId and authToken") and there was no error. This log was always printed if i run it on localhost.

Please tell me what can be different between localhost and Vercel deployment?

I had tried adding NEXTAUTH_SECRET on vercel env var. ADDED NEXTAUTH_URL (still did not make a difference) and then I removed it since documentation says they are not necessary

Enabled nextauth debug mode to see the logs above

How to reproduce

Open https://qa.tokogame.com and hit google login button on the top right. There should be no error but https://qa.tokogame.com/api/auth/session always shows empty {}

Expected behavior

Open https://qa.tokogame.com and hit google login button on the top right. On successful login, you should be redirected to https://qa.tokogame.com/members/profile

and

https://qa.tokogame.com/api/auth/session should not be empty

This expected behavior can always be reproduced on localhost but not on Vercel

github-actions[bot] commented 10 months ago

We could not detect a valid reproduction link. Make sure to follow the bug report template carefully.

Why was this issue closed?

To be able to investigate, we need access to a reproduction to identify what triggered the issue. We need a link to a public GitHub repository. Example: (NextAuth.js example repository).

The bug template that you filled out has a section called "Reproduction URL", which is where you should provide the link to the reproduction.

What should I do?

Depending on the reason the issue was closed, you can do the following:

In general, assume that we should not go through a lengthy onboarding process at your company code only to be able to verify an issue.

My repository is private and cannot make it public

In most cases, a private repo will not be a sufficient minimal reproduction, as this codebase might contain a lot of unrelated parts that would make our investigation take longer. Please do not make it public. Instead, create a new repository using the templates above, adding the relevant code to reproduce the issue. Common things to look out for:

I did not open this issue, but it is relevant to me, what can I do to help?

Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps by opening a new issue.

I think my reproduction is good enough, why aren't you looking into it quickly?

We look into every issue and monitor open issues for new comments.

However, sometimes we might miss a few due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.

Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.

Useful Resources