You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sign In With Google获取Subscribe With Google所需AccessToken的问题及invalid_grant错误排查

Sign In With Google获取Subscribe With Google所需AccessToken的问题及invalid_grant错误排查

看起来你在从旧版Google Sign In切换到SIWG(Sign In With Google)后,遇到了两个核心问题:一是passport-google-oidc默认没返回AccessToken,二是用回调里拿到的code调用getToken时出现了invalid_grant错误。我来帮你一步步排查解决:

一、为什么拿不到AccessToken?

passport-google-oidc是基于OpenID Connect协议实现的,它的核心是身份验证,默认会帮你完成code交换id_token、用户信息的流程,但你之前没用到正确的回调参数!

在passport-google-oidc的策略回调中,除了req、issuer、profile,还有一个**credentials参数**——里面就包含了你需要的accessToken、refreshToken等凭证!你之前的回调函数签名漏掉了这个参数,所以才没拿到AccessToken。

二、invalid_grant错误的核心原因:Code已被消耗

你尝试用回调里的code去调用oAuth2Client.getToken(code),这个操作本质上是重复使用了同一个授权code——而OIDC协议中的授权code是一次性有效的!

当passport-google-oidc执行验证流程时,它已经自动用这个code去Google服务器交换过用户信息和凭证了,所以当你再次用同一个code请求时,Google会返回invalid_grant,提示这个code已经失效。

三、正确的解决方案

1. 直接从passport回调中获取AccessToken

修改你的策略回调函数,添加credentials参数,直接拿到AccessToken:

const GoogleStrategy = require('passport-google-oidc');

const Config_Account_Passport = {
  Google : new GoogleStrategy({
    clientID : '6...MyClientID0c...apps.googleusercontent.com',
    clientSecret : 'a...MyClientSecret...',
    callbackURL: "https://...UrlOfMyServer.../google/auth",
    passReqToCallback : true
  }, async function(req, issuer, profile, credentials, done) { // 新增credentials参数
    try {
      // 获取用户基本信息
      const email = profile.emails[0].value;
      const oauth_id = profile.id;

      // 直接从credentials中拿AccessToken
      const accessToken = credentials.accessToken;
      // 这里可以直接用accessToken调用SWG接口,不需要再处理code
      await checkEntitlements(user, accessToken);

      return done(null, user);
    } catch(e) {
      return done(e, false);
    }
  })
};

module.exports = Config_Account_Passport;

2. 修改checkEntitlements函数,直接使用AccessToken

既然已经拿到了AccessToken,就不需要再通过code去换取了,简化你的checkEntitlements逻辑:

const Payment_SwG = require('./../modules/Payment/SwG');

async function checkEntitlements(user, accessToken) {
  try {
    // 直接使用accessToken调用SWG的权限检查接口
    const entitlements = await Payment_SwG.checkEntitlements(accessToken);
    // 处理权限信息,比如存入数据库或返回给前端
    // ...
  } catch(e) {
    throw e;
  }
}

3. 额外的配置检查

确保你的passport授权请求中,已经包含了SWG所需的scope和正确的参数:

passport.authenticate('google', { 
  scope: [
    'openid',
    'profile',
    'email',
    'https://www.googleapis.com/auth/subscribewithgoogle.publications.readonly'
  ], 
  accessType: 'offline', // 确保能拿到refresh_token(如果需要长期授权)
  prompt: 'consent' // 强制用户授权,确保能拿到有效凭证(可选,首次授权时有用)
});

四、补充说明

如果你需要长期保存授权(比如用户离线时也能检查权限),可以从credentials中拿到refreshToken,用它来刷新AccessToken,避免每次都要用户重新登录。

备注:内容来源于stack exchange,提问作者Gregor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 14:32:40