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

使用react-oauth/google实现Google登录未返回Refresh Token问题

问题分析与解决方案

你的核心问题是前端直接获取access_token的流程无法拿到refresh_token,谷歌OAuth2的规则是:refresh_token只能通过后端使用授权码(code)交换获取,前端隐式授权流程(直接返回access_token)不会返回refresh_token。你当前的配置虽然写了responseType: "code",但实际返回的是access_token,说明这个配置未生效,或者流程走了隐式授权。

步骤1:修正前端配置,获取授权码(code)

确保useGoogleLogin的配置正确触发授权码流程,调整代码如下:

import { useGoogleLogin } from "@react-oauth/google";

const googleSignIn = useGoogleLogin({
    onSuccess,
    isSignedIn: false, // 关闭自动登录,避免隐式流程干扰
    accessType: "offline",
    scope: "https://www.googleapis.com/auth/business.manage email profile openid",
    responseType: "code",
    prompt: "consent",
});

const onSuccess = (res) => {
    // 此时res应包含code,而非access_token
    console.log(res);
    // 将code传给后端接口
    api.post(apiUrl() + "api/v2/gmb/exchange-code/", { code: res.code })
        .then(response => {
            console.log(response.data);
            // 执行后续操作
        });
};

注意:

  • isSignedIn: false:如果设为true,组件会自动触发隐式授权流程,导致responseType: "code"失效。
  • 确保scope包含必要的权限(如email、profile),避免权限不足。

步骤2:后端PHP实现授权码交换token

后端需要用前端传来的code,向谷歌请求交换access_token和refresh_token,代码示例:

<?php
$code = $_POST['code'];
$client_id = "你的Google OAuth客户端ID";
$client_secret = "你的Google OAuth客户端密钥";
$redirect_uri = "你的授权回调地址(需与Google控制台配置一致)";

// 构建token请求URL
$token_url = "https://oauth2.googleapis.com/token";
$post_data = [
    'code' => $code,
    'client_id' => $client_id,
    'client_secret' => $client_secret,
    'redirect_uri' => $redirect_uri,
    'grant_type' => 'authorization_code'
];

// 发送POST请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 建议开启SSL验证,提升安全性

$response = curl_exec($ch);
curl_close($ch);

$token_data = json_decode($response, true);

// 此时token_data会包含access_token、refresh_token、expires_in等字段
if (isset($token_data['refresh_token'])) {
    // 存储refresh_token到数据库,用于后续刷新access_token
    $refresh_token = $token_data['refresh_token'];
    $access_token = $token_data['access_token'];
    
    // 用access_token获取用户信息(和你之前的逻辑一致)
    $user_info_url = 'https://www.googleapis.com/oauth2/v2/userinfo?fields=name,email,id,picture,verified_email';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $user_info_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $access_token));
    $user_data = json_decode(curl_exec($ch), true);
    curl_close($ch);
    
    // 返回用户信息和token相关数据给前端
    echo json_encode([
        'user' => $user_data,
        'access_token' => $access_token,
        'expires_in' => $token_data['expires_in']
    ]);
} else {
    // 处理错误,比如code无效或已过期
    echo json_encode(['error' => 'Failed to obtain refresh token', 'details' => $token_data]);
}
?>

步骤3:使用refresh_token刷新access_token

当access_token过期时,后端可以用存储的refresh_token请求新的access_token,代码示例:

<?php
$refresh_token = "存储在数据库的refresh_token";
$client_id = "你的Google OAuth客户端ID";
$client_secret = "你的Google OAuth客户端密钥";

$token_url = "https://oauth2.googleapis.com/token";
$post_data = [
    'refresh_token' => $refresh_token,
    'client_id' => $client_id,
    'client_secret' => $client_secret,
    'grant_type' => 'refresh_token'
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

$response = curl_exec($ch);
curl_close($ch);

$new_token_data = json_decode($response, true);
// 新的access_token在$new_token_data['access_token']中
?>

关键注意事项

  1. Google控制台配置:确保你的OAuth客户端ID的授权回调地址(redirect_uri)和后端配置的一致,且客户端类型为"Web应用"。
  2. refresh_token只返回一次:如果用户已经授权过,且没有设置prompt: "consent",谷歌不会再次返回refresh_token。如果需要重新获取,必须确保prompt: "consent",且用户重新授权。
  3. 安全性:refresh_token必须存储在后端,绝对不能暴露给前端,否则会导致账户安全风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 13:20:37