刷新Xero API令牌遇unsupported_grant_type错误及offline_access使用咨询
Xero OAuth2 offline_access 与刷新Token问题解决
用户问题
我不清楚如何使用offline_access,能否提供使用示例?另外,我该从哪里获取新的Refresh token?我已为所有用户添加了offline_access权限,想了解如何通过它生成新的Refresh token。我尝试了两种方法:
方法一:
$provider = new \League\OAuth2\Client\Provider\GenericProvider([ 'clientId' => $client, 'clientSecret' => $secret, 'redirectUri' => 'https://site/xeroreports', 'urlAuthorize' => 'https://login.xero.com/identity/connect/authorize', 'urlAccessToken' => 'https://identity.xero.com/connect/token', 'urlResourceOwnerDetails' => 'https://identity.xero.com/resources' ]); $newAccessToken = $provider->getAccessToken('refresh_token', [ 'refresh_token' => $xero_refresh ]);但仅获取到access token。
方法二:
$client = new \GuzzleHttp\Client(); $response1 = $client->request('POST', 'https://identity.xero.com/connect/token', [ 'body' => '{"grant_type":"refresh_token", "refresh_token":"'. $xero_refresh .'"}', 'headers' => [ 'Authorization' => 'Basic ' . $authpas, 'Content-Type' => "application/x-www-form-urlencoded", ], ]); echo $newRefreshToken = $response1->getBody();此时出现错误:
Type: GuzzleHttp\Exception\ClientException Code: 400 Message: Client error: `POST https://identity.xero.com/connect/token` resulted in a `400 Bad Request` response: {error: unsupported_grant_type}
问题解决与说明
一、offline_access权限的正确使用
offline_access不是在用户授权后添加,而是必须在首次授权请求的scope参数中包含,这样Xero才会返回有效的Refresh Token。示例代码(授权跳转环节):
$authorizationUrl = $provider->getAuthorizationUrl([ 'scope' => ['openid', 'profile', 'email', 'accounting.transactions', 'offline_access'] // 必须包含offline_access ]); // 引导用户跳转到$authorizationUrl完成授权
只有首次授权(或用户重新授权)时,Xero会返回初始Refresh Token;后续刷新操作中,服务端会返回新的Refresh Token用于下一次刷新。
二、两种方法的错误修正
方法一:提取隐藏的Refresh Token
你用League\OAuth2\Client获取的$newAccessToken对象里其实包含Refresh Token,只是没提取出来。修改代码:
$newAccessToken = $provider->getAccessToken('refresh_token', [ 'refresh_token' => $xero_refresh ]); // 提取新的Refresh Token $newRefreshToken = $newAccessToken->getRefreshToken(); // 同时获取新的Access Token $newAccessTokenValue = $newAccessToken->getToken();
方法二:修复请求格式错误
错误原因是Content-Type设为application/x-www-form-urlencoded,但请求体用了JSON格式,导致服务端无法识别grant_type。改成表单格式即可:
$client = new \GuzzleHttp\Client(); $response1 = $client->request('POST', 'https://identity.xero.com/connect/token', [ 'form_params' => [ // 用form_params自动处理表单编码 'grant_type' => 'refresh_token', 'refresh_token' => $xero_refresh ], 'headers' => [ 'Authorization' => 'Basic ' . $authpas, 'Content-Type' => 'application/x-www-form-urlencoded' ] ]); // 解析响应体提取Token $responseData = json_decode($response1->getBody(), true); $newRefreshToken = $responseData['refresh_token']; $newAccessToken = $responseData['access_token'];
如果坚持用body参数,需要把内容转为URL编码字符串:
'body' => http_build_query([ 'grant_type' => 'refresh_token', 'refresh_token' => $xero_refresh ]),
三、新Refresh Token的获取渠道
- 首次授权:用户完成授权跳转后,调用
getAccessToken('authorization_code')获取的Token对象中包含初始Refresh Token。 - 刷新操作:每次用有效的旧Refresh Token调用刷新接口,响应里会返回新的Refresh Token,需要替换存储的旧Token,避免过期失效。
内容的提问来源于stack exchange,提问作者Banyman
相关产品推荐
相关产品推荐

