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

基于React和Node.js:从Google JWT获取Access与Refresh令牌的问题

解决MERN应用中通过新版Google Identity Services获取API访问令牌的方案

首先明确:你当前使用@react-oauth/google的GoogleLogin默认返回的是ID Token(即你拿到的JWT),这个令牌仅用于验证用户身份,不包含访问Google Calendar等API所需的Access/Refresh令牌。要获取API授权令牌,需要切换到授权码流程,以下是具体实现步骤:

一、前端调整:获取授权码而非ID Token

修改GoogleLogin组件的配置,指定responseType="code"和所需的API权限scope,同时开启offline模式以获取Refresh Token:

<GoogleOAuthProvider clientId="MY_CLIENT_ID">
  <GoogleLogin
    onSuccess={this.onSuccess}
    onFailure={this.onFailure}
    responseType="code"
    scope="https://www.googleapis.com/auth/calendar" // 按需添加API权限,多个用空格分隔
    accessType="offline" // 必须添加此参数才能获取长期有效的Refresh Token
  />
</GoogleOAuthProvider>

此时onSuccess回调返回的对象会包含授权码:

{
  code: "AUTHORIZATION_CODE_STRING",
  clientId: "MY_CLIENT_ID",
  select_by: "btn"
}

将这个code发送到你的Node.js后端即可。

二、后端处理:用授权码兑换Access/Refresh令牌

使用谷歌官方的google-auth-library包完成令牌兑换,步骤如下:

  1. 安装依赖:
npm install google-auth-library
  1. 后端兑换令牌的代码示例:
const { OAuth2Client } = require('google-auth-library');
const User = require('./models/User'); // 你的用户模型

// 初始化OAuth2客户端
const oAuth2Client = new OAuth2Client(
  process.env.GOOGLE_CLIENT_ID,
  process.env.GOOGLE_CLIENT_SECRET,
  'postmessage' // SPA场景下固定填这个,需和Google Cloud控制台配置一致
);

// 处理前端发送的授权码
async function exchangeCodeForTokens(req, res) {
  const { code } = req.body;

  try {
    // 兑换授权码获取令牌
    const { tokens } = await oAuth2Client.getToken(code);
    /* tokens结构示例:
    {
      access_token: "ACCESS_TOKEN_STRING",
      refresh_token: "REFRESH_TOKEN_STRING",
      expires_in: 3600, // Access Token有效期1小时
      token_type: "Bearer"
    }
    */

    // 解码ID Token获取用户邮箱(可选,用于关联用户)
    const ticket = await oAuth2Client.verifyIdToken({
      idToken: tokens.id_token,
      audience: process.env.GOOGLE_CLIENT_ID,
    });
    const userEmail = ticket.getPayload().email;

    // 将令牌与用户关联后持久化存储(比如存入MongoDB)
    await User.findOneAndUpdate(
      { email: userEmail },
      { googleTokens: tokens },
      { upsert: true, new: true }
    );

    res.status(200).json({ message: '令牌存储成功' });
  } catch (error) {
    console.error('兑换令牌失败:', error);
    res.status(500).json({ error: '令牌兑换失败' });
  }
}

三、令牌使用与持久化注意事项

  • Access Token:有效期1小时,过期后需用Refresh Token刷新,无需用户重新授权。
  • Refresh Token:长期有效(除非用户撤销授权或令牌被吊销),需加密存储(比如用AES加密后存入数据库),禁止明文存储。
  • 后续访问Google API时,若Access Token已过期,可调用以下方法刷新:
async function refreshAccessToken(refreshToken) {
  oAuth2Client.setCredentials({ refresh_token: refreshToken });
  const { credentials } = await oAuth2Client.refreshAccessToken();
  // 更新数据库中的令牌
  await User.findOneAndUpdate(..., { googleTokens: credentials });
  return credentials.access_token;
}

四、为什么不用你当前拿到的JWT?

你当前获取的JWT是ID Token,解码后仅包含用户基本信息(邮箱、姓名等),不具备访问Google API的权限。ID Token的作用是验证用户身份,而非授权API访问,因此必须走授权码流程获取专用的Access/Refresh令牌。

内容的提问来源于stack exchange,提问作者gianlucazani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 21:55:25