- Published on
Auth.js 中的 access token 和 refresh token 实现
- Authors
- Name
- Shelton Ma
NextAuth.js 中的 access token 和 refresh token 实现
NextAuth.js 提供了对 OAuth 认证流程的支持,包括通过 access token 和 refresh token 处理外部身份验证系统的授权和认证.
基本概念
- Access Token:用于授权访问受保护资源,通常有效期较短.每当用户需要访问需要身份验证的 API 时,都会使用 access token.
- Refresh Token:用于获取新的 access token,通常有效期较长.当 access token 过期时,客户端可以使用 refresh token 获取新的 access token.
如何在 NextAuth.js 中配置 access token 和 refresh token
配置 NextAuth.js 并指定 access token 和 refresh token 的回调.
// pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
callbacks: {
// 获取授权后的 `access token` 和 `refresh token`
async jwt({ token, account }) {
if (account) {
// 保存 `access_token` 和 `refresh_token` 到 JWT 中
token.accessToken = account.access_token;
token.refreshToken = account.refresh_token;
token.expiresAt = Date.now() + account.expires_in * 1000; // 存储过期时间
}
// 检查 token 是否过期,如果过期则使用 refresh token 更新 access token
if (token.expiresAt && Date.now() > token.expiresAt) {
try {
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
refresh_token: token.refreshToken,
grant_type: 'refresh_token',
}),
});
const refreshedTokens = await response.json();
// 更新 JWT 中的 access_token 和过期时间
if (refreshedTokens.access_token) {
token.accessToken = refreshedTokens.access_token;
token.expiresAt = Date.now() + refreshedTokens.expires_in * 1000;
}
} catch (error) {
console.error('Error refreshing access token:', error);
}
}
return token;
},
// 会话回调:每次访问会话时都可以访问 JWT
async session({ session, token }) {
session.accessToken = token.accessToken;
session.refreshToken = token.refreshToken;
session.expiresAt = token.expiresAt;
return session;
},
},
session: {
strategy: 'jwt', // 使用 JWT 存储会话信息
},
secret: process.env.JWT_SECRET,
});