代表最终用户查询 Google Search Console:invalid_grant

Querying Google Search Console on behalf of end-user: invalid_grant

我正在尝试代表我的用户查询 Google Search Console,使用 Google 进行身份验证,具有 GSC 所需的范围。

我在 Firebase 身份验证中启用了 Google 登录,在我的脚本中使用客户端 ID 和密码。此外,我已经使用测试电子邮件、授权域和范围“https://www.googleapis.com/auth/webmasters”、“https://www.googleapis 设置了我的同意屏幕。 com/auth/webmasters.只读".

这是我的代码

React + Firebase 客户端

请注意,用户已通过电子邮件进行身份验证(我们将电子邮件帐户与 Google 帐户相关联)。

import {Grid, IconButton, List,
  ListItem, Tooltip, Typography} from "@mui/material";
import {GoogleAuthProvider, linkWithPopup,
  unlink} from "firebase/auth";
import React, {useState} from "react";
import {
  useUser,
} from "reactfire";
import {defaultErrorMessage} from "../../utils/constants";
import {log} from "../../utils/logs";
import {LoadingButton} from "@mui/lab";
import {Check, Clear} from "@mui/icons-material";


const GoogleSignIn = () => {
  const {data: user} = useUser();
  console.log("user", user);
  const onGoogleSearchConsole = async () => {
    const provider = new GoogleAuthProvider();
    provider.addScope("https://www.googleapis.com/auth/webmasters");
    provider.addScope("https://www.googleapis.com/auth/webmasters.readonly");
    provider.setCustomParameters({
      access_type: "offline",
    });

    linkWithPopup(user!, provider).then((result) => {
      console.log("onGoogleSearchConsole result", result);
    }).catch((error) => {
       console.log("onGoogleSearchConsole failed", error);
    });
  };
  const onDisconnectGoogleSearchConsole = () => {
    unlink(user!, "google.com").then(() => {
      // Auth provider unlinked from account
      console.log("onDisconnectGoogleSearchConsole");
    }).catch((error) => {
      console.log("onDisconnectGoogleSearchConsole failed", error);
    });
  };
  return (
    <React.Fragment>
      <Grid
        container
        direction="column"
      >
        <List>
          <ListItem
            secondaryAction={
              user &&
              user?.providerData.some((e) => e.providerId === "google.com") &&
              <Tooltip title="Unlink Google Search Console">
                <IconButton
                  onClick={onDisconnectGoogleSearchConsole}
                >
                  <Clear />
                </IconButton>
              </Tooltip>
            }
          >
            <Button
              color="primary"
              variant="contained"
              onClick={onGoogleSearchConsole}
              startIcon={
                user?.providerData.some((e) => e.providerId === "google.com") &&
                <Check/>
              }
              disabled={
                !user ||
                user?.providerData.some((e) => e.providerId === "google.com")
              }
            >
            Google Search Console
            </Button>
          </ListItem>
        </List>
      </Grid>
    </React.Fragment>
  );
};

export default GoogleSignIn;

尝试查询 GSC 的脚本。

#!/usr/bin/python

from googleapiclient.discovery import build
import google.oauth2.credentials

CLIENT_ID = 'MY_CLIENT_ID'
CLIENT_SECRET = 'MY_CLIENT_SECRET'

# Here I currently copy paste my access token and refresh token from client
at = "MY_ACCESS_TOKEN_COPY_PASTED_FROM_CLIENT"
rt = "MY_REFRESH_TOKEN_COPY_PASTED_FROM_CLIENT"
tu = "https://oauth2.googleapis.com/token"
scopes = [
  "https://www.googleapis.com/auth/webmasters",
  "https://www.googleapis.com/auth/webmasters.readonly",
]
c = google.oauth2.credentials.Credentials(
    None, # seems that we can just use refresh token, otherwise still fail with "at"
    scopes=scopes,
    refresh_token=rt,
    token_uri=tu,
    client_id=CLIENT_ID,
    client_secret=CLIENT_SECRET,
)

# v3 or v1 both fail
# webmasters = build('webmasters', 'v3', credentials=c)

webmasters = build('searchconsole', 'v1', credentials=c)

# FAIL HERE
site_list = webmasters.sites().list().execute()
print("site_list", site_list)

错误是

google.auth.exceptions.RefreshError: ('invalid_grant: Bad Request', {'error': 'invalid_grant', 'error_description': 'Bad Request'})

哪个应该说令牌有问题?我尝试了所有解决方案 invalid_grant trying to get oAuth token from google 没有更好的结果

我在这里 https://developers.google.com/webmaster-tools/v1/quickstart/quickstart-python 尝试了示例(它似乎只适用于桌面 oauth 客户端 ID),并且它有效,不知何故,我试图调整他们的代码,但这是一种不同的情况。

我做错了什么吗? 非常感谢:).

我使用“gapi”(Google JS 客户端)代替 Firebase 解决了这个问题。 为了简单起见,我使用了 https://github.com/ph-fritsche/react-gapi

// component ...
  const scopes = [
    "https://www.googleapis.com/auth/webmasters",
    "https://www.googleapis.com/auth/webmasters.readonly",
  ];
  const gapi = useGoogleApi({
    scopes: scopes,
  });
  const gAuth = gapi?.auth2?.getAuthInstance();
  gAuth?.currentUser.listen((e) => console.log("user", e));

  const onGoogleSearchConsole = async () => {
    const refreshToken = await gAuth!.grantOfflineAccess();
    console.log("refresh token", refreshToken);
  };
  const onDisconnectGoogleSearchConsole = () => {
    gAuth!.currentUser.get().disconnect();
  };
// ...