我正在使用nextjs 13以及next-auth v4。我有自己的外部express API
我正在使用Google sign in provider
我正在调用外部API进行登录,并为我提供访问和刷新令牌,在刷新令牌到期时,我想默默地获得一个新的访问令牌。我能够获取新的令牌,但无法使用新获取的令牌更新会话。
我参考了next-auth v4文档他们有这个例子
import { useSession } from "next-auth/react"
export default function Page() {
const { data: session, status, update } = useSession()
if (status === "authenticated") {
return (
<>
<p>Signed in as {session.user.name}</p>
{/* Update the value by sending it to the backend. */}
<button onClick={() => update({ name: "John Doe" })}>
Edit name
</button>
{/*
* Only trigger a session update, assuming you already updated the value server-side.
* All `useSession().data` references will be updated.
*/}
<button onClick={() => update()}>
Edit name
</button>
</>
)
}
return <a href="/api/auth/signin">Sign in</a>
}
当我尝试同样的我得到:typeError: update不是一个函数
我不知道你从哪里得到这个例子,但这是useSession
类型:
export declare function useSession<R extends boolean>(options?: UseSessionOptions<R>): SessionContextValue<R> | {
readonly data: null;
readonly status: "loading";
};
没有update
方法。如果要刷新令牌,则必须向提供程序发出post请求。因为只有提供程序服务器可以处理令牌。从这里
import NextAuth from "next-auth"
import Providers from "next-auth/providers"
const GOOGLE_AUTHORIZATION_URL =
"https://accounts.google.com/o/oauth2/v2/auth?" +
new URLSearchParams({
prompt: "consent",
access_type: "offline",
response_type: "code",
})
/**
* Takes a token, and returns a new token with updated
* `accessToken` and `accessTokenExpires`. If an error occurs,
* returns the old token and an error property
*/
async function refreshAccessToken(token) {
try {
const url =
"https://oauth2.googleapis.com/token?" +
new URLSearchParams({
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
grant_type: "refresh_token",
refresh_token: token.refreshToken,
})
const response = await fetch(url, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
method: "POST",
})
const refreshedTokens = await response.json()
if (!response.ok) {
throw refreshedTokens
}
return {
...token,
accessToken: refreshedTokens.access_token,
accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken, // Fall back to old refresh token
}
} catch (error) {
console.log(error)
return {
...token,
error: "RefreshAccessTokenError",
}
}
}
export default NextAuth({
providers: [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorizationUrl: GOOGLE_AUTHORIZATION_URL,
}),
],
callbacks: {
async jwt(token, user, account) {
// Initial sign in
if (account && user) {
return {
accessToken: account.accessToken,
accessTokenExpires: Date.now() + account.expires_in * 1000,
refreshToken: account.refresh_token,
user,
}
}
// Return previous token if the access token has not expired yet
if (Date.now() < token.accessTokenExpires) {
return token
}
// Access token has expired, try to update it
return refreshAccessToken(token)
},
async session(session, token) {
if (token) {
session.user = token.user
session.accessToken = token.accessToken
session.error = token.error
}
return session
},
},
})