You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next-Auth页面刷新时如何更新refreshToken?

问题描述

概述

我已实现next-auth,从授权服务获取accessToken并将其作为参数传入mutation,后续API调用使用后端生成的token。
已按照next-auth的刷新令牌轮换机制实现了token轮换功能。

问题

我的token过期时间设为1分钟:

  • 会话在后台运行未操作时,API能正常调用并更新新的refreshToken(符合预期);
  • 但1分钟后刷新页面,会话会直接退出。

查看终端发现,页面刷新时旧refreshToken没有更新为新的,客户端仍保留刷新前的refreshToken,但后台运行时无此问题 😕

有没有解决方法?或者我哪里配置错误?

提前感谢!

代码片段

pages/api/[..nextauth].tsx代码

import NextAuth, { NextAuthOptions } from "next-auth"
import { JWT } from "next-auth/jwt"
import GithubProvider from "next-auth/providers/github"
import { Provider, RefreshToken } from "../../../generated/graphql"

const loginQuery = `mutation login($AccessToken: String!, $Provider: Provider!) {
  login(accessToken: $AccessToken, provider: $Provider) {
    refreshToken
    token
    tokenExpiry
  }
}`

const refreshTokenQuery = `mutation refreshToken($RefreshToken: String!) {
  refreshToken(refreshToken: $RefreshToken) {
    refreshToken
    token
    tokenExpiry
  }
}`
const authMutation = (query, variables) : Promise<RefreshToken | null> => {
  return fetch(process.env.NEXT_PUBLIC_API_URL, {
    method: 'POST',
    body: JSON.stringify({
      query: query,
      variables: variables
    })
  })
    .then(res => res.json())
    .then(data => {
      if (data.errors) {
        return null;
      } else {
        let response = data.data.refreshToken || data.data.login;
        if (response.refreshToken === undefined || 
        response.tokenExpiry === undefined || 
        response.token === undefined) return null
        return <RefreshToken> response;
      }
    })
    .catch(error => {
      console.log(error);
      return null;
    });
};

async function login(account, user: any) {
  let provider: Provider;
  if (account?.provider === 'github') provider = Provider.GitHub  
  if(provider === undefined) return
  const variables = {
    AccessToken: account.access_token,
    Provider: provider
  };
  const response = await authMutation(loginQuery, variables)
  if (response === null) return 
  console.log("new refresh token..", response.refreshToken)
  return {
    accessToken: response.token,
    accessTokenExpires: response.tokenExpiry * 1000,
    refreshToken: response.refreshToken,
    user,
  }
}

async function refreshAccessToken(token: any) {
  const variables = {
    RefreshToken: token.refreshToken,
  };
  console.log("variables", variables)
  const response = await authMutation(refreshTokenQuery, variables)
  if (response === null) return 
  console.log("new refresh token..", response.refreshToken)
  return {
    ...token,
    accessToken: response.token,
    accessTokenExpires: response.tokenExpiry * 1000,
    refreshToken: response.refreshToken,
  }
}

export const authOptions: NextAuthOptions = {
  providers: [
    GithubProvider({
      clientId: process.env.NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_ID,
      clientSecret: process.env.NEXT_PUBLIC_GITHUB_OAUTH_CLIENT_SECRET,
    }),
  ],
  theme: {
    colorScheme: "light",
  },
  callbacks: {
    jwt: async ({ account, token, user }: any): Promise<JWT> => {
      console.log("current refreshToken", token.refreshToken, token.accessTokenExpires)
       // Initial Sign In
      if (account && user) {
        console.log("initial login", account)
        return login(account, user) 
      }
      
       // Return previous token if the access token has not expired yet
      if (Date.now() < token.accessTokenExpires){
        console.log("token not expired")
        return token
      }

      // Rotate refresh_token and fetch new access_token if current one is expired
      if (token){
        console.log("token expired")
        return refreshAccessToken(token) 
      }
    },
    session: async ({ session, token }: any) => {
      if (!session?.user || !token?.accessToken) return
      session.accessToken = token.accessToken as string
      session.error = token.error as string | undefined
      session.user = token.user
      return session
    },
  },
}

export default NextAuth(authOptions)

_app.tsx代码

import "../styles/globals.css"
import { SessionProvider as NextSessionProvider } from "next-auth/react"
import UrqlProvider from "../lib/provider"
import { AppProps } from "next/app"

function App({ Component, pageProps }: AppProps) {

  const { session } = pageProps

  return (
    <>
      <NextSessionProvider session={session}>
        <UrqlProvider>
            <Component {...pageProps} />
        </UrqlProvider>
      </NextSessionProvider>
    </>
  )
}

export default App

内容的提问来源于stack exchange,提问作者Yeganathan S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 16:46:28