Refresh Token Rotation
Obtain new access token from refresh token.
NextAuth.js does not handle refresh token rotation automatically. But the functionality can be implemented using callbacks.
- Create a 
refreshAccessTokenhelper. 
pages/api/auth/[...nextauth].js
// Helper to obtain a new access_token from a refresh token.async function refreshAccessToken(token) {  try {    const formData = new URLSearchParams()
    formData.append("grant_type", "refresh_token")    formData.append("client_id", process.env.OAUTH_CLIENT_ID)    formData.append("client_secret", process.env.OAUTH_CLIENT_SECRET)    formData.append("refresh_token", token.refreshToken)
    const response = await fetch(      `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/oauth/token`,      {        method: "POST",        body: formData,        headers: {          "Content-Type": "application/x-www-form-urlencoded",        },      }    )
    const data = await response.json()
    if (!response.ok) {      throw new Error()    }
    return {      ...token,      accessToken: data.access_token,      accessTokenExpires: Date.now() + data.expires_in * 1000,      refreshToken: data.refresh_token ?? token.refreshToken,    }  } catch (error) {    return {      ...token,      error: "RefreshAccessTokenError",    }  }}- Update our 
jwtandsessioncallbacks to handle refresh tokens. 
pages/api/auth/[...nextauth].js
export default NextAuth({  callbacks: {    async jwt({ token, user }) {      // Forward the access token, refresh token and expiration date from user.      // We'll use these to handle token refresh.      if (user) {        token.accessToken = user.access_token        token.accessTokenExpires = Date.now() + user.expires_in * 1000        token.refreshToken = user.refresh_token      }
      // If token has not expired, return it,      if (Date.now() < token.accessTokenExpires) {        return token      }
      // Otherwise, refresh the token.      return refreshAccessToken(token)    },    async session({ session, token }) {      if (token?.accessToken) {        session.accessToken = token.accessToken
        // Decode token and pass info to session.        const decoded = jwt_decode(token.accessToken)        session.user.id = decoded.id        session.user.email = decoded.email        session.user.username = decoded.username        session.error = token.error      }      return session    },  },})