Raul Cano

Feb 19, 2025 • 2 min read

A Smart Way to Update NextAuth.js JWT Token

How to update your NextAuth.js session data without forcing re-authentication or database queries

A Smart Way to Update NextAuth.js JWT Token

I'd like to start with the thanks and credits to [toomus](https://github.com/nextauthjs/next-auth/discussions/4229) the GitHub buddy who actuallly figured out how to do it.

The problem

I'm using NextAuth.js for authentication, and the app has an onboarding flow where users can't get out of it untill the onboarding is done.

By default after the user signs in for the first time his onboarding step is set to inital, and that's being set by NextAuth.js as a JWT token.

While at the same time the middleware checks that so we are protecting other routes untill the onboarding is done.

I wasn't able to figured out how to update the JWT. One idea was to logged out the user and sign him in again, after the mutation is done. That would work, but that would be a bit of a pain for the users.

Here is where [toomus](https://github.com/toomus) came to the rescue.

His approach was simple but smart.

The trick is to create a special credentials provider that only exists to update our session. It doesn't actually authenticate anything - it just passes through whatever data we give it.

Here's what we need:

// auth.config.ts
providers: [
  GitHub,
  CredentialsProvider({
    id: 'session-update',
    credentials: {},
    async authorize(credentials) {
      return credentials?.user ? JSON.parse(credentials.user) : null
    },
  }),
],

Btw. We are using the T3 starter for next with react query and tRPC for the api calls.

Then in our component where we need to update the session (in my case, completing the onboarding):

const { mutate: completeOnboarding } = api.onboarding.completeOnboarding.useMutation({
  onSuccess: async (updatedUser) => {
    await signIn('session-update', {
      redirect: false,
      user: JSON.stringify({
        ...updatedUser,
        onboardingStep: "COMPLETED"
      })
    })
    router.replace("/explore")
  }
})

But how

When you call signIn with our special 'session-update' provider, NextAuth.js:

- Takes our updated user data

- Passes it through the authorize function

- Updates the JWT token

- Updates the session

No database queries, no signing out and back in - just smooth session updates.

Final thoughts

This solution is so clean it makes me wonder why it's not more widely known. Big thanks again to toomus for sharing this approach.

Let me know what you think about this approach!

Join Raul on Peerlist!

Join amazing folks like Raul and thousands of other people in tech.

Create Profile

Join with Raul’s personal invite link.

0

7

0