我目前正在开发 nuxt 应用程序,我需要将其与客户提供商集成以进行身份验证(OAuth)。对于身份验证,我使用 next-auth(AuthJs),一切工作正常,当刷新此应用程序所需的
access_token
时,它失败了。 access_token
的有效期为2小时
在
jwt
回调中,将 refreshed_token
分配给 token
并传递给 sesssion
回调后。但在下一个会话检查(自动运行)中,jwt 回调中的令牌具有旧值。初始登录时指定的值将保留。但至于刷新就成了问题了。
由于该值不会通过
refresh_token
重新分配,所以 expire_at
属性也是如此。所以它会不断刷新令牌,直到它使最初的refresh_token
无效。
这个问题有解决办法吗?
为什么初始登录中的值(返回)(正在检查回调中的
account
参数)运行良好并且令牌被保留?
server/api/auth/[...].ts
import type { AuthConfig, TokenSet } from "@auth/core/types";
import { NuxtAuthHandler } from "#auth";
import { JWT } from "@auth/core/jwt";
const runtimeConfig = useRuntimeConfig();
const BASE_URL = "Base url";
async function refreshAccessToken(token: JWT): Promise<TokenSet> {
const params = new URLSearchParams({
client_id: process.env.NUXT_AUTH_CLIENT_ID!,
client_secret: process.env.NUXT_AUTH_CLIENT_SECRET!,
grant_type: "refresh_token",
refresh_token: token.refresh_token as string,
});
const response = await fetch(`${BASE_URL}/oauth/token`, {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params.toString(),
method: "POST",
});
const tokens: TokenSet = await response.json();
if (!response.ok) {
throw tokens;
}
return {
...token,
access_token: tokens.access_token,
refresh_token: tokens.refresh_token,
error: null,
expires_at: Math.floor(Date.now() / 1000 + 30), // 30 for testing
// expires_at: Math.floor(Date.now() / 1000 + tokens.expires_in!),
};
}
export const authOptions: AuthConfig = {
secret: runtimeConfig.authJs.secret,
debug: true,
callbacks: {
async jwt({ token, account }) {
console.log('-----------------------------------');
console.log("token in jwt is ", token);
const now = Date.now();
let resToken = null;
if (account) {
console.log("initial login", token, account);
// Initial login
resToken = {
...token,
access_token: account.access_token,
refresh_token: account.refresh_token,
expires_at: Math.floor(Date.now() / 1000 + 30),
// expires_at: Math.floor(Date.now() / 1000 + account.expires_in!),
error: null,
};
} else if (now < (token.expires_at as number) * 1000) {
console.log("token is valid ", token);
// Have valid token
resToken = token;
} else {
// RefreshToken
try {
console.log("before refresh token is ", token);
// the returned refreshed token is not persisting so expires_at, access_token and refresh_token remains the same as the first
// So this code blocks keeps running for around 3 times as the expires_at not changed
// it will invalidate the accessToken and refresh token it becomes a "RefreshAccessTokenError"
resToken = await refreshAccessToken(token);
console.log("resToken is ", resToken);
console.log('-----------------------------------');
} catch (error) {
console.error("Error refreshing access token", error);
return { ...token, error: "RefreshAccessTokenError" as const };
}
}
return resToken;
},
async session({ session, token }) {
return {
...session,
access_token: token.access_token,
refresh_token: token.refresh_token,
error: token.error,
};
},
},
providers: [
{
id: "projectId",
name: "projectName",
type: "oauth",
issuer: BASE_URL,
clientId: process.env.NUXT_AUTH_CLIENT_ID,
clientSecret: process.env.NUXT_AUTH_CLIENT_SECRET,
token: `${BASE_URL}/oauth/token`,
authorization: {
url: `${BASE_URL}/oauth/authorize`,
params: { scope: "api_v3" },
},
redirectProxyUrl: "http://localhost:3000/api/auth",
userinfo: `${BASE_URL}/api/v3/users/me`,
},
],
};
export default NuxtAuthHandler(authOptions, runtimeConfig);
通过禁用 ssr 解决多重快速会话检查