从API获取产品数据的初始调用无效 - 无法确定如何将OAuth 2.0连接到调用
I am trying to connect to the Google Shopping Products API to create some new product items. Before I do that more complex task, I am just trying to connect to get a list of the existing products.
I have setup a Service Account within Google API console and downloaded the json key file. I have saved the file to the server. I have then taken all of the examples from Google's documents and tried to piece them together.
VARIABLE NOTES:
$KEY_FILE_LOCATION - this is the location of the json service account key file.
$merchantid - this is the merchantid of my Google Merchant Centre
CODE:
$client->setAuthConfig($KEY_FILE_LOCATION);
$client->setApplicationName('Merchant Centre');
$client->setScopes('https://www.googleapis.com/auth/content');
echo "<br/><br/>client: ".json_encode($client);
$url = "https://www.googleapis.com/content/v2/".$merchantid."/products";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
echo "<br/><br/>data: ".$data;
What I am having trouble with, is how to connect the authentication to the actual google shopping call. The connection to the content/v2/merchantid/products call returns this response:
{ "error": { "errors": [ { "domain": "global", "reason": "required", "message": "Login Required", "locationType": "header", "location": "Authorization" } ], "code": 401, "message": "Login Required" } }
So how do I connect the oauth 2.0 authentication service account json to the actual call. I can't find anything in the documentation or online, about how you actually connect the two things together. I have integrations with other Google API's but none of the code I have provides a clear example of implementing this.
EDIT: Following the documentation through further I have managed to work out a flow that may work. I need to use JWT to obtain a token for the call to the API - the code below is being used to access the token, but it is still failing on the last section. The response from this call is { "error": "invalid_grant", "error_description": "Invalid JWT Signature." }. The signature section of the JWT is the only section that looks different to the example Google has given - my code outputs a signature of 43 characters whereas googles is significantly longer.
$header = json_encode(['alg' => 'RS256', 'typ' => 'JWT']);
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$iat = strtotime("now");
$exp = strtotime("+1 hour");
$currenttime = date("H:i:s");
$claimset = json_encode(['iss' => 'REDACTED',
'scope' => 'https://www.googleapis.com/auth/content',
'aud' => 'https://www.googleapis.com/oauth2/v4/token',
'exp' => $exp,
'iat' => $iat]);
$base64UrlClaimSet = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($claimset));
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlClaimSet, $privatekey, true);
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
$jwt = $base64UrlHeader . "." . $base64UrlClaimSet . "." . $base64UrlSignature;
$url = "https://www.googleapis.com/oauth2/v4/token";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=".$jwt);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
echo "<br/><br/>data: ".$data;
I am trying to follow the 'computing the signature' section of this https://developers.google.com/identity/protocols/OAuth2ServiceAccount
Okay, I have managed to work through this over 2 days, and have the solution. I am posting it here to help out others in the future who may struggle with this. This is for using php with a google service account to obtain a token using JWT and then make a call to get all products from your Google Merchant Shopping account.
$merchantid = xxxxxxxxx; //this is a 9 digit code found in top left of Merchant Center
$email = 'xxxxxxxxxxx@merchant-center-xxxxxxxxxxxx.iam.gserviceaccount.com'; //this is the email address assigned to the service account
$privatekey = "-----BEGIN PRIVATE KEY-----
XXXXXapprox 6 lines long key from json fileXXXXXX
-----END PRIVATE KEY-----
"; //this is the long key that you download within the json file at the end of the service account setup
$header = json_encode(['alg' => 'RS256', 'typ' => 'JWT']);
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$iat = strtotime("now");
$exp = strtotime("+1 hour");
$currenttime = date("H:i:s");
$claimset = json_encode(['iss' => $email,
'scope' => 'https://www.googleapis.com/auth/content',
'aud' => 'https://www.googleapis.com/oauth2/v4/token',
'exp' => $exp,
'iat' => $iat]);
$base64UrlClaimSet = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($claimset));
$binary_signature = "";
$algo = "SHA256";
openssl_sign($base64UrlHeader.".".$base64UrlClaimSet, $binary_signature, $privatekey, $algo);
$jwtSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($binary_signature));
$jwt = $base64UrlHeader . "." . $base64UrlClaimSet . "." . $jwtSignature;
$url = "https://www.googleapis.com/oauth2/v4/token";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=".$jwt);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$accesstoken = substr($data, strpos($data, 'access_token') + 16);
$arr = explode('"',trim($accesstoken));
$accesstoken = $arr[0];
$url = "https://www.googleapis.com/content/v2/".$merchantid."/products";
$header = array(
'Authorization: Bearer '.$accesstoken
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
echo "<br/><br/>data: ".$data;
401 means the request is unauthorized. You need to send an Authorization
header with your request, it depends what kind of auth token the authorization requires (should be in the api docs). To set the header in PHP using cURL (for example bearer token):
$header = array(
'Authorization: Bearer <insert-token-here>'
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);