Quickbooks PHP API:刷新 OAuth 2 令牌失败

Quickbooks PHP API: Refresh OAuth 2 Token Failed

我正在尝试使用 PHP SDK 访问 Quickbooks API,但出现以下错误:

Refresh OAuth 2 Access token with Refresh Token failed. Body: [{"error":"invalid_grant"}].

我的令牌似乎可以工作 24 小时,但之后我收到上述错误。每次调用 API 时,我都会将更新后的令牌保存到数据库中:

//Client ID & Secret
$qbClientId = $this->scopeConfig->getValue('quickbooks/api/qb_client_id', $storeScope);
$qbClientSecret = $this->scopeConfig->getValue('quickbooks/api/qb_client_secret', $storeScope);

//Retrieve currently saved Refresh_Token from DB
$qbRefreshToken = $this->scopeConfig->getValue('quickbooks/api/qb_refresh_token', $storeScope);

$OAuth2LoginHelper = new OAuth2LoginHelper($qbClientId, $qbClientSecret);
$accessTokenObj = $OAuth2LoginHelper->refreshAccessTokenWithRefreshToken($qbRefreshToken);

$error = $OAuth2LoginHelper->getLastError();

if($error) {
  throw new \Exception($error);
} else {
  // The refresh token and access token expiration
  $refreshTokenValue = $accessTokenObj->getRefreshToken();
  $refreshTokenExpiry = $accessTokenObj->getRefreshTokenExpiresAt();

  // Save new Refresh Token & Expiry to DB
  $this->configInterface->saveConfig('quickbooks/api/qb_refresh_token', $this->encryptor->encrypt($refreshTokenValue), 'default', 0);
  $this->configInterface->saveConfig('quickbooks/api/qb_refresh_token_expiry', $refreshTokenExpiry, 'default', 0);

  // The access token and access token expiration
  $accessTokenValue = $accessTokenObj->getAccessToken();
  $accessTokenExpiry = $accessTokenObj->getAccessTokenExpiresAt();

  // Save new Access Token & Expiry to DB
  $this->configInterface->saveConfig('quickbooks/api/qb_access_token', $this->encryptor->encrypt($accessTokenValue), 'default', 0);
  $this->configInterface->saveConfig('quickbooks/api/qb_access_token_expiry', $accessTokenExpiry, 'default', 0);

  return DataService::Configure(array(
    'auth_mode' => 'oauth2',
    'ClientID' => $qbClientId,
    'ClientSecret' => $qbClientSecret,
    'accessTokenKey' => $accessTokenValue,
    'refreshTokenKey' => $refreshTokenValue,
    'QBORealmID' => 'MyRealmID',
    'baseUrl' => 'Development'
  ));
}

正如您所见,在每次 API 调用中,我都使用 refreshAccessTokenWithRefreshToken($qbRefreshToken) 方法获取新的刷新和访问令牌并将它们保存到我的数据库以供下次使用,但是我24 小时后仍然收到 invalid_grant 错误。

有什么想法吗?

https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/faq

Why does my refresh token expire after 24 hours?

Stale refresh tokens expire after 24 hours. Each time you refresh the access_token a new refresh_token is returned with a lifetime of 100 days. The previous refresh_token is now stale and expires after 24 hours. When refreshing the access_token, always use the latest refresh_token returned to you.

您确定使用的是最新的刷新令牌吗?

So as you can see, on each API call, I'm using the refreshAccessTokenWithRefreshToken($qbRefreshToken) method to get new Refresh and Access Tokens and saving those to my DB for next use...

为什么每次请求都要请求新的访问令牌和刷新令牌?为什么不检查旧访问令牌是否仍然有效?

如上所述,您甚至存储了访问令牌的过期时间。所以你应该知道它是否仍然有效。

因此,当您发出 API 请求并且您的访问令牌已过期时,您将收到一条错误消息。在 return,您现在可以申请一个新的。

我遇到了同样的问题。在我的例子中,我已经更新了数据库中的标记,但不是 内存中的所有地方 (特别是在 $dataService 对象中)。因此,继续使用 $dataService 对象进行 API 调用是在使用旧令牌。哦!

虽然我认为它仍然有效,但您不需要在每次 API 调用时都刷新令牌(正如 David 指出的那样)。我的解决方案是进行 API 调用,如果失败,则刷新令牌并再次进行 API 调用。这是我的代码的简化版本:

$user        = ...; // get from database
$dataService = getDataServiceObject();

$response = $dataService->Add(...); // hit the QBO API
$error    = $dataService->getLastError();

if ($error) {
  refreshTokens();
  $response = $dataService->Add(...); // try the API call again
}

// ... "Add" complete, onto the next thing

////////////////////////////////

function getDataServiceObject() {
  global $user;

  return DataService::Configure(array(
    'auth_mode'       => 'oauth2',
    'ClientID'        => '...',
    'ClientSecret'    => '...',
    'accessTokenKey'  => $user->getQbAccessToken(),
    'refreshTokenKey' => $user->getQbRefreshToken(),
    'QBORealmID'      => $user->getQbRealmId(),
    'baseUrl'         => '...',
  ));
}

function refreshTokens() {
  global $dataService;
  global $user;

  $OAuth2LoginHelper = $dataService->getOAuth2LoginHelper();
  $obj               = $OAuth2LoginHelper->refreshAccessTokenWithRefreshToken($user->getQbRefreshToken());
  $newAccessToken    = $obj->getAccessToken();
  $newRefreshToken   = $obj->getRefreshToken();

  // update $user and store in database
  $user->setQbAccessToken($newAccessToken);
  $user->setQbRefreshToken($newRefreshToken);
  $user->save();

  // update $dataService object
  $dataService = getDataServiceObject(); 
}