GitHub OAuth 本地调试:回调地址、Session Cookie 和 302 循环怎么查
GitHub 登录失败时,表面上经常只是“又回到登录页”。真正原因可能是回调地址不一致、Session 没写进去、Cookie 没带回来,或者线上域名和本地地址混用了。
下面按 Express + passport-github2 的常见接法排查,不依赖某个特定项目。
1. 先把三个地址写清楚
本地开发通常有三个地址:
站点地址: http://127.0.0.1:3000
登录地址: http://127.0.0.1:3000/auth/github
回调地址: http://127.0.0.1:3000/auth/github/callback
GitHub OAuth App 里也必须填同一个回调地址。差一个 host、端口、路径、协议都不行。
本地统一用 127.0.0.1,不要一会儿 localhost 一会儿 127.0.0.1。Cookie 和 OAuth 回调排障时,少一个变量就少很多麻烦。
2. 环境变量不要混线上
.env 示例:
APP_BASE_URL=http://127.0.0.1:3000
GITHUB_CLIENT_ID=你的本地 OAuth App Client ID
GITHUB_CLIENT_SECRET=你的本地 OAuth App Client Secret
GITHUB_CALLBACK_URL=http://127.0.0.1:3000/auth/github/callback
SESSION_SECRET=本地随机长字符串
COOKIE_SECURE=false
检查进程实际读到什么:
node -e "require('dotenv').config(); console.log({base:process.env.APP_BASE_URL, callback:process.env.GITHUB_CALLBACK_URL, secure:process.env.COOKIE_SECURE})"
不要把 GITHUB_CLIENT_SECRET 打到日志里。上面只看地址和开关。
3. 登录地址应该返回 302 到 GitHub
启动服务后执行:
curl -I http://127.0.0.1:3000/auth/github
预期状态:
HTTP/1.1 302 Found
location: https://github.com/login/oauth/authorize?...
如果不是 302,查路由有没有挂上,不要急着改 GitHub 后台配置。
4. 回调地址错误时怎么看
GitHub 页面如果提示 callback URL 不匹配,先核对两处:
- GitHub OAuth App 里的 Authorization callback URL。
- 服务运行时传给 GitHubStrategy 的 callbackURL。
Express 里常见写法:
new GitHubStrategy({
clientID: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackURL: process.env.GITHUB_CALLBACK_URL
}, verifyUser)
如果代码里用 APP_BASE_URL + '/auth/github/callback' 拼,也要确认 APP_BASE_URL 没带结尾斜杠导致双斜杠。
5. 回调成功但又回登录页,先查 Session
登录成功后,服务通常会:
- 收到 GitHub 回调。
- 查找或创建用户。
- 把用户 id 写进 session。
- 给浏览器设置 session cookie。
- 跳转到首页或控制台。
浏览器最后又回 /login,说明第 3 或第 4 步可能没成。
用 curl 保存 cookie 看流程:
rm -f /tmp/codenest-cookie.txt
curl -i -c /tmp/codenest-cookie.txt http://127.0.0.1:3000/auth/github
cat /tmp/codenest-cookie.txt
OAuth 交互本身需要浏览器点授权,curl 不能完全替代。但 cookie 文件能帮你确认服务有没有设置基础 session cookie。
浏览器里看更直接:打开开发者工具,检查 Application / Cookies 里是否有类似:
connect.sid
codenest.sid
具体名字取决于项目配置。
6. 本地不要开 secure cookie
如果本地是 HTTP:
http://127.0.0.1:3000
Session cookie 不能要求 Secure,否则浏览器不会在 HTTP 下保存它。
Express session 示例:
app.use(session({
name: 'codenest.sid',
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
sameSite: 'lax',
secure: process.env.COOKIE_SECURE === 'true'
}
}));
本地 .env:
COOKIE_SECURE=false
线上 HTTPS 再改成 true。
7. 给 OAuth 流程加最小日志
不要记录 access token。只记录阶段和用户 id。
logger.info('github_oauth_callback_received', {
path: req.path
});
logger.info('github_oauth_user_resolved', {
user_id: user.id,
github_id: profile.id
});
logger.info('github_oauth_login_finished', {
user_id: req.user && req.user.id
});
如果失败,记录错误类型,不记录密钥:
logger.error('github_oauth_failed', {
message: err.message,
stack: err.stack
});
排查时看:
tail -n 80 data/logs/app.log
tail -n 80 data/logs/error.log
8. 302 循环的排查顺序
第一步:确认登录后请求有没有 cookie
浏览器 Network 里点开跳转后的页面,看 Request Headers 是否带 Cookie。
没有 Cookie:查 Set-Cookie、Secure、域名、SameSite。
有 Cookie:查服务端 session store。
第二步:确认 session store 里有记录
如果用 SQLite 存 session,查表:
sqlite3 data/blog.db ".tables"
sqlite3 data/blog.db "select sid, expires from web_sessions order by expires desc limit 5;"
表名按项目实际改。能看到新 session,说明写入至少发生过。
第三步:确认反序列化用户成功
Passport 常见代码:
passport.deserializeUser((id, done) => {
const user = db.prepare('SELECT * FROM users WHERE id = ?').get(id);
done(null, user || false);
});
如果 session 里有用户 id,但数据库里找不到用户,也会表现成未登录。
9. 本地验收
用浏览器完成一次 GitHub 授权后,执行:
curl -I http://127.0.0.1:3000/login
curl -I http://127.0.0.1:3000/auth/github
sqlite3 data/blog.db "select id, username, github_id from users order by id desc limit 3;"
tail -n 50 data/logs/app.log
tail -n 50 data/logs/error.log
检查点:
/auth/github返回 302 到 GitHub。- 授权后用户表出现或更新 GitHub 用户。
- 浏览器里能看到 session cookie。
- 登录后访问受保护页面不再跳回
/login。 error.log没有 OAuth callback、session 反序列化相关错误。
还没有评论,欢迎先发第一条。