Next.js+Express架构下使用Passport.js实现YouTube OAuth的报错咨询
问题修复方案
你遇到的问题由4处配置错误共同导致,按以下步骤修改即可正常运行:
- 错误1:后端缺少Passport初始化配置
你未在Express中注册Passport中间件,同时原有授权路由的冗余回调会拦截Passport的自动重定向逻辑,修复后的后端主代码如下:
const express = require("express"); const app = express(); const cors = require("cors"); const passport = require("passport"); const passportSetup = require("./passport-setup"); app.use( cors({ origin: ["http://localhost:3000"], credentials: true }) ); // 新增Passport初始化代码 app.use(passport.initialize()); app.get( "/login/youtube", passport.authenticate("youtube", { scope: ["profile", "https://www.googleapis.com/auth/youtube.readonly"], accessType: "offline", }) ); // 新增Google授权回调路由,用于兑换令牌后跳回前端 app.get("/login/youtube/callback", passport.authenticate("youtube", { session: false }), (req, res) => { // 可在此处将用户信息、令牌存入数据库 // 重定向回前端成功页,令牌可通过query参数传递 res.redirect(`http://localhost:3000/success?access_token=${req.user.accessToken}`); } ) app.listen(4000, () => console.log("listening on port 4000"));
- 错误2:OAuth授权请求不能用fetch发起
OAuth流程需要浏览器跳转到Google官方授权页,fetch是异步AJAX请求,无法触发页面跳转,会导致跨域和无响应错误,修复后的前端代码如下:
const Login = () => { const makeOauthRequest = () => { // 直接跳转至后端授权路由,不要用fetch window.location.href = "http://localhost:4000/login/youtube"; }; return ( <> <div> <button>Instagram</button> <button>Facebook</button> <button>Twitter</button> <button>Spotify</button> <button onClick={makeOauthRequest}>YouTube</button> </div> </> ); }; export default Login;
- 错误3:Passport配置参数错误
你当前配置的callbackURL是前端页面地址,该地址应为后端回调接口地址,同时策略的verify回调不能为空,必须调用done方法完成验证,修复后的passport-setup.js代码如下:
const passport = require("passport"); const YoutubeStrategy = require("passport-youtube-v3").Strategy; require("dotenv").config(); passport.use( new YoutubeStrategy( { // 修改为后端回调地址 callbackURL: "http://localhost:4000/login/youtube/callback", scope: ["https://www.googleapis.com/auth/youtube.readonly"], authorizationParams: { access_type: "offline", }, clientID: process.env.YOUTUBE_CLIENT_ID, clientSecret: process.env.YOUTUBE_CLIENT_SECRET, }, // 补充必填的verify回调 (accessToken, refreshToken, profile, done) => { return done(null, {profile, accessToken, refreshToken}); } ) );
内容的提问来源于stack exchange,提问作者nick_velos
相关产品推荐
相关产品推荐

