已完成Google认证仍触发GaxiosError: Login Required问题求助
Gmail API调用报错"Login Required"的解决方法
问题描述
完成Google OAuth2认证流程后,调用gmail.users.messages.list接口时,仍收到错误:GaxiosError: Login Required。相关代码如下:
原index.js
const express = require("express"); const cors = require("cors"); const passport = require("passport"); const cookieSession = require("cookie-session"); const { google } = require('googleapis'); const path = require('path'); require("./passport-setup"); const CLIENT_URL = "http://localhost:3000/inbox"; const passportSetup = require("./passport-setup"); const GoogleStrategy = require("./passport-setup").OAuth2Strategy; const app = express(); const gmail = google.gmail({ version: 'v1' }); app.use(cors({credentials: true, origin: 'http://localhost:3000'})); app.use(express.urlencoded({ extended: false })); app.use(express.json()); app.use( cookieSession({ name: "session", keys: ["key1", "key2"], }) ); app.use(passport.initialize()); app.use(passport.session()); app.get("/", (req, res) => res.send("Hello World")); app.get("/failed", (req, res) => res.send("Failed!")); app.get("/google", passport.authenticate('google', { scope: ['profile', 'email', 'https://mail.google.com/' ], accessType: 'offline', prompt: 'consent' })) app.get("/google/callback", passport.authenticate("google", { successRedirect: CLIENT_URL, failureRedirect: "/failed" })) app.get("/success", (req,res)=>{ if(req.user) { res.status(200).json({ success: true, message: "Login success!", user: req.user, cookies: req.cookies }); }; }); app.get("/inbox", async (req, res) => { try { const userId = 'me'; const accessToken = req.user.accessToken; // Assuming the access token is stored in req.user const response = await gmail.users.messages.list({ userId, maxResults: 10, auth: accessToken, // Include the access token in the request }); res.json(response.data); } catch (error) { console.error("Error fetching Gmail messages:", error); res.status(500).json({ error: "Failed to fetch Gmail messages" }); } }); app.get("/logout", (req,res)=>{ req.logout(); res.redirect(CLIENT_URL); }) app.listen(5000, () => console.log(`Server running at port ${5000}!`));
原passport-setup.js
const passport = require("passport"); const GoogleStrategy = require("passport-google-oauth20").Strategy; passport.serializeUser(function (user, done) { done(null, user); }); passport.deserializeUser(function (user, done) { done(null, user); }); passport.use( new GoogleStrategy( { clientID: "insert client id", clientSecret: "insert client secret", callbackURL: "http://localhost:5000/google/callback", }, function (accessToken, refreshToken, profile, done) { return done(null, profile); } ) );
问题根源
- Passport未存储访问令牌:在GoogleStrategy的验证回调中,仅将
profile存入会话,丢失了accessToken和refreshToken,导致req.user.accessToken不存在。 - Google API认证参数错误:直接传递字符串格式的token给
auth参数不符合googleapis库要求,需要传入OAuth2客户端实例。
修复方案
1. 修改Passport逻辑,保存令牌信息
更新passport-setup.js的验证回调,将令牌与用户信息合并存储:
const passport = require("passport"); const GoogleStrategy = require("passport-google-oauth20").Strategy; passport.serializeUser(function (user, done) { done(null, user); }); passport.deserializeUser(function (user, done) { done(null, user); }); passport.use( new GoogleStrategy( { clientID: "insert client id", clientSecret: "insert client secret", callbackURL: "http://localhost:5000/google/callback", }, function (accessToken, refreshToken, profile, done) { // 合并令牌与用户信息 const user = { ...profile, accessToken, refreshToken }; return done(null, user); } ) );
2. 正确配置Google API认证
修改index.js的/inbox路由,使用OAuth2客户端实例完成认证,同时添加令牌过期自动刷新逻辑:
// 顶部新增OAuth2客户端初始化 const { google } = require('googleapis'); const oauth2Client = new google.auth.OAuth2( "insert client id", // 替换为你的Client ID "insert client secret" // 替换为你的Client Secret ); // 修改/inbox路由 app.get("/inbox", async (req, res) => { try { if (!req.user?.accessToken) { return res.status(401).json({ error: "用户未授权或令牌缺失" }); } // 设置客户端凭证 oauth2Client.setCredentials({ access_token: req.user.accessToken, refresh_token: req.user.refreshToken }); const response = await gmail.users.messages.list({ userId: 'me', maxResults: 10, auth: oauth2Client, // 使用OAuth2客户端实例 }); res.json(response.data); } catch (error) { console.error("获取Gmail邮件失败:", error); // 处理令牌过期,自动刷新 if (error.code === 401 && req.user.refreshToken) { try { const { credentials } = await oauth2Client.refreshAccessToken(); // 更新会话中的令牌 req.user.accessToken = credentials.access_token; // 重新请求API const response = await gmail.users.messages.list({ userId: 'me', maxResults: 10, auth: oauth2Client, }); res.json(response.data); } catch (refreshError) { res.status(401).json({ error: "令牌过期且刷新失败,请重新登录" }); } } else { res.status(500).json({ error: "获取Gmail邮件失败" }); } } });
额外注意事项
- 确认Google Cloud Console已启用Gmail API
- 认证scope已包含
https://mail.google.com/(原代码已正确设置) - 可通过
/success接口验证req.user是否包含accessToken和refreshToken
内容的提问来源于stack exchange,提问作者acorn
相关产品推荐
相关产品推荐

