Wenn ich die Seite aktualisiere, werden fast gleichzeitig zwei Aktualisierungsanfragen gesendet.
Die erste Anfrage ruft korrekt /auth/refresh auf und erhält ein neues AccessToken und RefreshToken.
Unmittelbar danach wird eine zweite Anfrage gesendet, die jedoch weiterhin die alte Aktualisierung verwendet Token.
Das Backend gibt dann 401 zurück, wodurch beide Token ungültig werden.
Danach sind keine weiteren API-Aufrufe erfolgreich, bis ich mich erneut anmelde.
Ich versuche zu verstehen:
Warum wird der NextAuth-JWT-Rückruf beim Neuladen der Seite zweimal aufgerufen?
Wie kann ich das verhindern? Können mehrere Aktualisierungsaufrufe gleichzeitig erfolgen?
Hier ist der relevante Teil meiner Konfiguration:
Code: Select all
// auth.config.ts
import type { NextAuthConfig } from "next-auth"
import Credentials from "next-auth/providers/credentials"
import validateCredential from "../server/actions/user/validateCredential"
async function refreshAccessToken(token: any) {
const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL!
try {
const res = await fetch(`${BACKEND_URL}/auth/refresh`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ refresh_token: token.refreshToken }),
cache: "no-store",
})
if (!res.ok) throw new Error("Refresh failed")
const data = await res.json()
const newAccessToken = data.access_token || token.accessToken
const newRefreshToken = data.refresh_token || token.refreshToken
const payload = JSON.parse(
Buffer.from(newAccessToken.split(".")[1], "base64").toString()
)
const newExp = payload?.exp ? payload.exp * 1000 : undefined
return {
...token,
accessToken: newAccessToken,
refreshToken: newRefreshToken,
accessTokenExpires: newExp,
}
} catch (e) {
return { ...token, error: "RefreshAccessTokenError" }
}
}
const authConfig: NextAuthConfig = {
providers: [
Credentials({
async authorize(credentials) {
const user = await validateCredential(credentials as any)
return user ?? null
},
}),
],
callbacks: {
async jwt({ token, user }) {
if (user) {
return {
...token,
accessToken: user.accessToken,
refreshToken: user.refreshToken,
accessTokenExpires: user.accessTokenExpires,
}
}
const now = Date.now()
if (token.accessTokenExpires && now < token.accessTokenExpires - 10000) {
return token
}
if (token.refreshToken) {
return await refreshAccessToken(token)
}
return { ...token, error: "RefreshAccessTokenError" }
},
},
}
export default authConfig
Code: Select all
// validateCredential.ts
export default async function validateCredential(values) {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/login/verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
cache: 'no-store',
body: JSON.stringify(values),
})
if (!res.ok) return null
const data = await res.json()
return {
id: String(data.user.id),
accessToken: data.access_token,
refreshToken: data.refresh_token,
accessTokenExpires: data.access_token_exp,
}
}
Mobile version