当前位置: 首页 > 知识库问答 >
问题:

使用google oauth2节点库,不能用刷新令牌获取新的访问令牌

宰父熙云
2023-03-14

使用google oauth2库,我可以在用户第一次通过时成功地对其进行身份验证,获得他们的刷新令牌和第一次访问令牌。直到令牌过期,一切都按预期工作。

但是,当访问令牌过期时,我需要获得一个新的访问令牌,并使用现有的刷新令牌将这些令牌存储在我的数据存储区中。我知道文档中规定了令牌过期时应该重新提取它们自己,但是当我为每个调用创建一个新客户机(以确保令牌不会在用户之间重用)时,我认为客户机在令牌有机会刷新自己之前就已经被拆除了。

检查库调用实际的google api时,我应该能够通过调用client.refreshAccessStoken()方法获得新的访问令牌,这个调用的响应会给出invalid_grantbad request错误。我将这个方法发出的实际api请求与google oauth2 playground上的api请求进行了比较,这两个调用是相同的--尽管它们刷新令牌的调用有效,而我的调用不有效。

附上的是我的代码,因为它现在目前的立场,请发送帮助-我没有任何头发留下拔出!

const { google } = require('googleapis')
const scopes = [
  'https://www.googleapis.com/auth/spreadsheets.readonly',
  'https://www.googleapis.com/auth/userinfo.email',
  'https://www.googleapis.com/auth/drive.readonly'
]

module.exports = (env, mongo) => {
  const getBaseClient = () => {
    const { OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CALLBACK_URL } = env.credentials
    return new google.auth.OAuth2(
      OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CALLBACK_URL
    )
  }

  const getNewAccessTokens = async (authId, refreshToken) => {
    const { tokens } = await getBaseClient().getToken(refreshToken)
    await mongo.setAccessTokensForAuthUser(authId, { ...tokens, refresh_token: refreshToken })
    return tokens
  }

  const getAuthedClient = async (authId) => {
    let tokens = await mongo.getAccessTokensForAuthUser(authId)

    if (!tokens.access_token) {
      tokens = await getNewAccessTokens(authId, tokens.refresh_token)
    }

    const client = getBaseClient()
    client.setCredentials(tokens)

    if (client.isTokenExpiring()) {
      const { credentials } = await client.refreshAccessToken()
      tokens = { ...credentials, refresh_token: tokens.refreshToken }
      await mongo.setAccessTokensForAuthUser(authId, tokens)
      client.setCredentials(tokens)
    }

    return client
  }

  const generateAuthUrl = (userId) => {
    return getBaseClient().generateAuthUrl({
      access_type: 'offline',
      scope: scopes,
      state: `userId=${userId}`
    })
  }

  const getUserInfo = async (authId) => {
    const auth = await getAuthedClient(authId)
    return google.oauth2({ version: 'v2', auth }).userinfo.get({})
  }

  const listSheets = async (authId) => {
    const auth = await getAuthedClient(authId)
    let nextPageToken = null
    let results = []
    do {
      const { data } = await google
        .drive({ version: 'v3', auth })
        .files.list({
          q: 'mimeType = \'application/vnd.google-apps.spreadsheet\'',
          includeItemsFromAllDrives: true,
          supportsAllDrives: true,
          corpora: 'user',
          orderBy: 'name',
          pageToken: nextPageToken
        })
      nextPageToken = data.nextPageToken
      results = results.concat(data.files)
    } while (nextPageToken)
    return results
  }

  return {
    generateAuthUrl,
    getUserInfo,
    listSheets
  }
}

共有1个答案

秋阳旭
2023-03-14

我解决了自己的问题。

我将access_codesrefresh_tokens混为一谈,认为从auth url接收的代码是refresh_token,存储它,并试图重用它以获得更多access_tokens。这是不对的。别这样。

您从身份验证url获得access_code,当您第一次将其与client.getToken(code)方法一起使用时,您将收到refresh_tokenaccess_token

我还应该提到的是,我在auth url中添加提示符:'consession',这样当有人重新进行身份验证时,您总是可以收到access_code,您可以使用该access_code来获取refresh_token(如果您没有进行身份验证,那么调用client.gettoken()不会返回

const { google } = require('googleapis')
const scopes = [
  'https://www.googleapis.com/auth/spreadsheets.readonly',
  'https://www.googleapis.com/auth/userinfo.email',
  'https://www.googleapis.com/auth/drive.readonly'
]

module.exports = (env, mongo) => {
  const getBaseClient = () => {
    const { OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CALLBACK_URL } = env.credentials
    return new google.auth.OAuth2(
      OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CALLBACK_URL
    )
  }

  const getAuthedClient = async (authId) => {
    let tokens = await mongo.getAccessTokensForAuthUser(authId)

    const client = getBaseClient()
    client.setCredentials(tokens)

    if (client.isTokenExpiring()) {
      const { credentials } = await client.refreshAccessToken()
      tokens = { ...credentials, refresh_token: tokens.refresh_token }
      await mongo.setAccessTokensForAuthUser(authId, tokens)
      client.setCredentials(tokens)
    }

    return client
  }

  const generateAuthUrl = (userId) => {
    return getBaseClient().generateAuthUrl({
      access_type: 'offline',
      prompt: 'consent',
      scope: scopes,
      state: `userId=${userId}`
    })
  }

  const getUserInfo = async (accessCode) => {
    const auth = getBaseClient()
    const { tokens } = await auth.getToken(accessCode)
    auth.setCredentials(tokens)
    const { data } = await google.oauth2({ version: 'v2', auth }).userinfo.get({})
    return { ...data, tokens }
  }

  const listSheets = async (authId) => {
    const auth = await getAuthedClient(authId)
    let nextPageToken = null
    let results = []
    do {
      const { data } = await google
        .drive({ version: 'v3', auth })
        .files.list({
          q: 'mimeType = \'application/vnd.google-apps.spreadsheet\'',
          includeItemsFromAllDrives: true,
          supportsAllDrives: true,
          corpora: 'user',
          orderBy: 'name',
          pageToken: nextPageToken
        })
      nextPageToken = data.nextPageToken
      results = results.concat(data.files)
    } while (nextPageToken)
    return results
  }

  return {
    generateAuthUrl,
    getUserInfo,
    listSheets
  }
}
 类似资料:
  • 目前访问类型处于联机状态。当我需要访问驱动器上的文件/文件夹时,我将浏览器重定向到Google URL并获得访问代码: 一切运转良好!但我只需要第一次重定向。 当我谷歌时,在google Drive API文档中,我发现我可以通过浏览器重定向获得刷新令牌,并将其保存在数据库中。(换句话说,我可以使用脱机访问)。 而且每次当我需要从google drive读取数据时,我使用刷新令牌获得访问令牌,而无

  • 我的问题是如何使用OAuth2.0从刷新令牌中获取访问令牌。我还没有找到任何从刷新令牌中获取访问令牌的例子。 我参考了[Google+API参考],但他们使用HTTP方法提到了它。2请用C#提供一些使用Google+API提供的方法的例子。

  • 我如何从第一次授权代码中获得刷新令牌和访问令牌?并且,我如何重用这个刷新令牌来获得一个新的访问令牌,以便使用Java API上传到Google Drive?这不是一个web应用程序。它在Java Swing代码中。

  • 我正在使用Cognito用户池对系统中的用户进行身份验证。成功的身份验证将提供一个ID令牌(JWT)、一个访问令牌(JWT)和一个刷新令牌。这里的文档清楚地提到了刷新令牌可以用于刷新访问令牌,但没有提到如何使用。我的问题是,一旦我的访问令牌过期,我如何使用存储的刷新令牌再次刷新我的访问令牌? 我搜索了JavaScript SDK,但找不到任何方法来做同样的事情。我肯定错过了什么。 我还想通过Lam

  • 我编写了一个控制台ASP.NET应用程序来获取AccessTokens。我有clientId,我的应用程序的客户端秘密,我做了以下操作: var authContext=新的AuthenticationContext(“https://login.windows.net/common/oauth2/authorize”);var acquireTask=authContext.AcquireTok