A New Collection of Thoughtful Learning Apps — Now Available on iOS & Android

Image
I’m excited to share a set of mobile apps I’ve recently completed and published on both the Google Play Store and the Apple App Store. These apps are designed with a simple goal in mind: to make meaningful, structured content more accessible, whether you’re studying theology or improving your English vocabulary. 📱 Now Available on Both Platforms All apps are live and available for download: Google Play Developer Page: https://play.google.com/store/apps/dev?id=5835943159853189043 Apple App Store Developer Page: https://apps.apple.com/ca/developer/q-z-l-corp/id1888794100 📖 Theology & Confession Study Apps For those interested in Reformed theology and classical Christian teachings, I’ve developed a series of apps that present foundational texts in a clean, focused reading format: The Belgic Confession Canons of Dort Heidelberg Catechism Westminster Shorter Catechism Each app is designed to provide a distraction-free experience, making it easier to read, reflect, and revisit these im...

NextAuth.js — Ensuring Linked Accounts Always Have the Latest Access Token

NextAuth.js — Ensuring Linked Accounts Always Have the Latest Access Token

By default, when a user logs out and signs in again in NextAuth.js, the linked account may retain an old access token. This can cause issues if the access token has expired. To always have the latest token, you need to update the linked account during the signIn callback.


1️⃣ The default behavior

NextAuth.js stores linked accounts in the database. On subsequent logins:

  • The account is matched
  • Access token is reused if not expired
  • No automatic refresh occurs unless you explicitly handle it

> Problem: If the access token is expired, API calls using that token will fail.


2️⃣ Update linked account on sign-in

You can use the signIn callback in NextAuth.js to refresh tokens and update the database:



import { PrismaAdapter } from "@next-auth/prisma-adapter";

import NextAuth from "next-auth";

import KeycloakProvider from "next-auth/providers/keycloak";

import prisma from "../../../lib/prisma";

export default NextAuth({

  adapter: PrismaAdapter(prisma),

  providers: [

    KeycloakProvider({

      clientId: process.env.KEYCLOAK_CLIENT_ID,

      clientSecret: process.env.KEYCLOAK_CLIENT_SECRET,

      issuer: process.env.KEYCLOAK_ISSUER

    })

  ],

  callbacks: {

    async signIn({ user, account }) {

      if (account) {

        // Update linked account with latest tokens

        await prisma.account.updateMany({

          where: { provider: account.provider, providerAccountId: account.providerAccountId },

          data: {

            access_token: account.access_token,

            refresh_token: account.refresh_token,

            expires_at: account.expires_at

          }

        });

      }

      return true;

    },

    async jwt({ token, account }) {

      if (account) {

        token.accessToken = account.access_token;

        token.refreshToken = account.refresh_token;

        token.expires = account.expires_at * 1000;

      }

      return token;

    },

    async session({ session, token }) {

      session.accessToken = token.accessToken;

      session.refreshToken = token.refreshToken;

      return session;

    }

  }

});

> Key points:

  • Use the signIn callback to update the linked account
  • Store the latest access_token, refresh_token, and expires_at
  • JWT and session callbacks propagate the latest token to the session

3️⃣ Benefits

  • Every login will use the latest access token
  • API calls from the frontend or backend using the token won’t fail due to expiration
  • Keeps linked accounts synchronized with the IdP

4️⃣ Optional: Refresh tokens automatically

You can also implement **automatic token refresh** using the JWT callback when the token is near expiry:



if (Date.now() > token.expires) {

  const refreshed = await refreshAccessToken(token);

  token.accessToken = refreshed.accessToken;

  token.refreshToken = refreshed.refreshToken;

  token.expires = refreshed.expires;

}

> Combined with updating the linked account on sign-in, this ensures your Next.js app always has valid tokens.


Conclusion

NextAuth.js makes it easy to manage linked accounts, but you must handle token updates yourself if you want **fresh tokens on every login**. Using the signIn callback to update the database ensures your access tokens and refresh tokens are always current, avoiding unexpected 401 errors.

Part of the Next.js Frontend SSO Series

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular Posts

2026 Begins: Choosing to Stay on the Path as a Blogger

Health Checks and Scaling Strategies for Next.js in Kubernetes