I'm using PHP UPS API (https://github.com/gabrielbull/php-ups-api) to get rates and to hopefully generate labels.
I've logged into UPS and set up credentials. I have Client Id and Client Secret and successfully generated my access_token via curl. I have endpoints set up for testing and production and things seem to be working fine, until I try to issue a Rate call
$shipFrom and $shipTo are set up properly...
try {
$shipment = new \Ups\Entity\Shipment();
$shipFrom = new \Ups\Entity\ShipFrom();
$shipFrom->setAddress($address_from);
$shipment->setShipFrom($shipFrom);
$shipTo = $shipment->getShipTo();
$shipTo = $shipTo->setAddress($address_to);
$package = new \Ups\Entity\Package();
$package->getPackagingType()->setCode(\Ups\Entity\PackagingType::PT_PACKAGE);
$package->getPackageWeight()->setWeight($weight);
// if you need this (depends of the shipper country)
$weightUnit = new \Ups\Entity\UnitOfMeasurement;
$weightUnit->setCode(\Ups\Entity\UnitOfMeasurement::UOM_LBS);
$package->getPackageWeight()->setUnitOfMeasurement($weightUnit);
$dimensions = new \Ups\Entity\Dimensions();
$dimensions->setHeight($height);
$dimensions->setWidth($width);
$dimensions->setLength($length);
$unit = new \Ups\Entity\UnitOfMeasurement;
$unit->setCode(\Ups\Entity\UnitOfMeasurement::UOM_IN);
$dimensions->setUnitOfMeasurement($unit);
$package->setDimensions($dimensions);
$shipment->addPackage($package);
var_dump($rate->getRate($shipment));
} catch (Exception $e) {
var_dump($e);
}
The exception is caught and I see this:
object(Ups\Exception\InvalidResponseException)#31 (7) {
["message":protected]=>
string(47) "Failure: Invalid Access License number (250003)"
This object is requiring $accessKey, $userId, $password.
I was assuming $accessKey would be my $accessToken. I'm believing that is incorrect. So where can I get an access key?
When I go here:
https://www.ups.com/dpui/upsdeveloperkit?loc=en_US
When I select: "I want to integrate UPS technology into my business"
It will only have the text below available:
"Note: We are excited to show you our new Developer Portal where you can get OAuth credentials to integrate with our APIs. Please click here to get started"
When I click 'get started', I'm back to my developer portal
https://developer.ups.com/en-us/
If I click on Apps -> My App Name, I see the id and secret again. Nothing mentioning access key.
I feel like I'm missing a major step somewhere.
Related
I found following thread at : https://issuetracker.google.com/issues/133299031#comment14
Hello, In-app update priority of the release can be set using the Play Developer Publishing API's Edits methods. There is a new 'inAppUpdatePriority' field under Edits.tracks.releases. The documentation does not mention the new field yet but you should still be able to set it. In-app update priority can not be set from the Google Play Console at the moment.
I am using google-api-php-client with Service Account authentication, I would like to ask how to set 'inAppUpdatePriority' using google-api-php-client I have tried following in my PHP code.
$publisher->edits_tracks->update(self::PACKAGE_NAME, self::EDIT_ID, 'production', new \Google_Service_AndroidPublisher_Track);
After hours of testing with Google API PHP Client, I managed to edit the inAppUpdatePriority field, with Laravel, this way:
try {
$packageName = "your.package.name";
$versionCode = "version_code_as_string"; //example "50"
$client = new \Google\Client();
//you need to setup your own Service Account or other API access methods
$client->setAuthConfig("path/to/your/json/file");
$client->addScope(AndroidPublisher::ANDROIDPUBLISHER);
$service = new \Google\Service\AndroidPublisher($client);
//create new edit
$appEdit = $service->edits->insert($packageName, new \Google\Service\AndroidPublisher\AppEdit());
//uncomment if you want to get hold of available tracks
// $tracksResponse = $service->edits_tracks->listEditsTracks($packageName, $appEdit->id);
// dd($tracksResponse);
$trackRelease = new \Google\Service\AndroidPublisher\TrackRelease();
$trackRelease->versionCodes = [$versionCode];
//set desired update priority
$trackRelease->inAppUpdatePriority = 5;
$trackRelease->status = "completed";
$postBody = new \Google\Service\AndroidPublisher\Track();
$postBody->setReleases([$trackRelease]);
//desired track to update. One of the followings: production,beta,alpha,internal
$track = "production";
$update = $service->edits_tracks->update($packageName, $appEdit->id, $track, $postBody);
//commit changes to Google Play API
$service->edits->commit($packageName, $appEdit->id);
// dd($update);
} catch (Exception $ex) {
if ($ex->getCode() == 404) {
//this catches if some info is wrong (tested with a version code that has not been upload to Google Play Console)
}
}
Notes:
You should note that for this to work (without implementing your propre way of uploading app via Google Play API), you need to first upload your app via Google Play Console to your desired track, then click Save, then Review release and */!\DON'T CLICK Rollout release/!*, then run the above mentioned code which will Commit (Rollout) the changes (if you try to rollout release after running the above code, you will get an error that you can ignore).
Any changes to inAppUpdatePriority won't be applied if your release is already rolled out.
You should have already published at least one release in the desired track before you can use this (tested with Internal testing only)
I'd like to validate my in-app purchases.
I'm using this receipt validator which by looking at the source code is calling https://www.googleapis.com/androidpublisher/v3/applications/<appId>/purchases/products/<productId>/tokens/<token>, here's my code basically copied from the readme
$googleClient = new Google_Client();
$googleClient->setScopes([Google_Service_AndroidPublisher::ANDROIDPUBLISHER]);
$googleClient->setApplicationName('my project name');
$googleClient->setAuthConfig('files/googleauthconfig.json');
$validator = new Validator(new Google_Service_AndroidPublisher($googleClient));
try {
$response = $validator->setPackageName('my.app.id')
->setProductId('my.product.id')
->setPurchaseToken('token i got from my app when purchasing')
->validatePurchase();
} catch (Exception $e) {
var_dump($e->getMessage());
exit;
}
var_dump($response);
exit;
I've hardcoded a lot of stuff because I'm just trying to get it to work at this point. googleauthconfig.json is the JSON file dev console gave me for my service account which contains a bunch of IDs for the account as well as a private key. I went in my play console and made my service account an administrator and then waited about 24 hours as suggested in other questions for the same problem. I've configured my products, which are consumable and active and I successfully purchase them through my signed release app with the test credit card.
The error I keep getting is
The current user has insufficient permissions to perform the requested operation.
The current user has insufficient permissions to perform the requested operation.
Means exactly that the user you are authenticating with does not have the permissions to do what you are trying to do. You are using a service account. A service account is not you. Service accounts are preauthorized.
Go over to google pay probably the admin section take the Service account email address and grant it permissions to access the data. You probably do this like you would any other user.
As mentioned in the comment it can take time normally under an hour for a service account to kick in. After you grant it access.
possible code error.
I think you should try the pure code rather that using your validator to ensure that its not thats the problem.
$client = new Google_Client();
$client->setScopes([Google_Service_AndroidPublisher::ANDROIDPUBLISHER]);
$client->setApplicationName('my project name');
$client->setAuthConfig('files/googleauthconfig.json');
$service = new Google_Service_AndroidPublisher($client);
try {
$response = $service->purchases_products->get(package_name, product_id, purchase_token);
} catch (Exception $e) {
var_dump($e->getMessage());
exit;
}
var_dump($response);
exit;
Well, oddly enough, as suggested in other answers as well, I just needed to wait in my case about 30 hours before the permission changes took effect.
I can't get the Locations list from my business under my code (PHP using the "Google APIs Client Library for PHP" together with "Google_Service_MyBusiness" Classes) when I use the "Service Account" authentication, the API returns an empty Location List.
I already have the Prerequisites and did the Basic setup, by the way, I got the information with success on OAuth Playground, under a specific AccountId, Eg: 1111111111, provided by another response there on the "OAuth Playground".
(PS: I tested with my "PERSONAL" and "LOCATION_GROUP" accounts and got success with both).
But when I try to do it over my code via Server Account authentication, I can't get all the information, just the Account data that return another AccoundId, Eg: 2222222222, different of the Accounts that I got on OAuth Playground.
I did the Authentication process on OAuth Playground, using the same project where I created the "Service Account", by the way, the Permission of this "Service Account" is OWNER.
Previously, my role in my company on the Google My Business was "SITE_MANAGER", so I saw a forum answer where just "MANAGER" level/role can list the Locations, so I requested to change my permission, but continues as not the success on Locations listing.
So, I saw another Google My Business support article recommending create a "Location Group" and put my current "Location" into this group to make easy handle it, I did it and no success again.
My code is simple, based on Google guide, OAuth 2.0 for Server to Server Applications, and some Forum Questions (BTW the author's question have the same issue than me):
<?php
putenv('GOOGLE_APPLICATION_CREDENTIALS=service-account-credentials.json');
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope("https://www.googleapis.com/auth/plus.business.manage");
require_once('Google_Service_MyBusiness.php');
$mybusinessService = new Google_Service_MyBusiness($client);
$accounts = $mybusinessService->accounts;
$accountsList = $accounts->listAccounts()->getAccounts();
foreach ($accountsList as $accKey => $account) {
var_dump('$account->name', $account->name);
$locations = $mybusinessService->accounts_locations;
$locationsList = $locations->listAccountsLocations($account->name)->getLocations();
var_dump('$locationsList', $locationsList);
// Final Goal of my Code
if (empty($locationsList)===false) {
foreach ($locationsList as $locKey => $location) {
$reviews = $mybusinessService->accounts_locations_reviews;
$listReviewsResponse = $reviews->listAccountsLocationsReviews($location->name);
$reviewsList = $listReviewsResponse->getReviews();
var_dump('$reviewsList', $reviewsList);
}
}
}
I expected the Location of my business (also the reviews, but it a next step), but I just got the empty Location list.
Finally, I got success using the ClientId/ClientSecret keys together with Refresh Token previously received on Google OAuth 2 Playground on the first time that I give permission to (my) App, instead "Service Account" authentication way :)
$client = new Google_Client();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->addScope("https://www.googleapis.com/auth/plus.business.manage");
$client->setSubject('my email user on GMB');
$client->refreshToken(' ###### ')
Now I got all the needed data for my application.
I've been developing a feature for an extension in TYPO3 to post activities to a Google Plus domain profile.
I use the following code to instantiate the Google Client
$googleClient = new Google_Client();
$googleClient->setApplicationName("NAME");
$googleClient->setClientId("123456789");
$googleClient->setClientSecret("qwertyuiop");
$googleClient->setRedirectUri("CALLBACK_URL");
$googleClient->setScopes(array(
'https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/plus.stream.write',
));
$googleClient->setRequestVisibleActions('http://schema.org/AddAction');
$googleClient->setApprovalPrompt('force');
$googleClient->setAccessType('offline');
All values are like token are verified.
Then store the profiles obtaining the refreshToken to make the POST many times. Now the code of POST
$googleClient->refreshToken($this->refreshToken);
$googleClient->verifyIdToken();
$plusdomains = new Google_Service_PlusDomains($googleClient);
$post = new Google_Service_PlusDomains_Activity();
$post['object']['originalContent'] = 'HELLO WORLD';
try {
$result = $plusdomains->activities->insert('me', $post);}
catch (\Exception $e){
var_dump($e);
}
The line that is inside the try generates an error that is:
Access to the Google+ Domains API is not allowed as the user has
consented to incompatible scopes. See:
https://developers.google.com/+/domains/authentication/
I have searched for additional information about the error, which indicates that are the permissions or scopes, even in other questions of this same forum a few years ago. However I checked on https://developers.google.com/+/domains/authentication/scopes and the ones I'm using are there. I would appreciate you guiding me in solving this problem.
I have a browser-based app (single page, AngularJS) and am using hello to use third party signin such as Google, FB, Soundcloud, etc.
My app uses a PHP API server.
What's a good way to have the user able to login using Google, but also verify the user on the server side?
I was considering:
The browser app performs an implicit grant with google/fb/etc
I then transfer the access_token from the client to the server, then use, for example, a google-api-php-client with my app id, secret and the user access_token? Using their API such as /me? (which grant type would this be?)
Retrieve some key from the third-party (facebook_id, email, etc), match it against a user in my database, and then consider the user authenticated?
Also, should I perform this on each API request? Or should I just stash the access_token for a bit and assume that the user is still valid until the key expires?
One issue is that not all of those providers support the implicit flow. But assuming they do, the access_token you get for each will be proof that the user authenticated with that system, not necessarily that they have access to call your API. You still need something that asserts that "someone#gmail.com can 'read' resource X in your system"
You probably need something that translates whatever you get from Google, Soundcloud, etc. into a token your app understands. A simple(r) format is to use JWT. (Json Web Tokens).
App -> Intermmediary -> Soundcloud/Google
<-JWT--+ <---whavetever-+
and then:
App - (JWT) -> API
JWT are easy to manipulate, validate and verify. See jwt.io
You might want to look at this blog post also for some additional information (specifically on AngularJS front-ends)
The blog post #eugenio-pace mentioned was really helpful for setting up the client side.
For the server side though, the access_token should be validated.
The SDK's are (in composer) (code below):
Facebook: "facebook/php-sdk-v4" : "4.0.*"
Google: cURL request (didn't care for "google/apiclient")
SoundCloud: "ise/php-soundcloud": "3.*"
(There are others of course, just these three were the ones I chose, and seem decent.)
Last time I did something like this I made the mistake of validating the access_token on every request, which had a huge (obviously negative) impact on performance. Now I just validate it on login and use it to retrieve the user's ID from that service. So, the browser sends me access_token A and says it's from Facebook, I use the sdk above the the access_token with Facebook, and I get back their ID so I know they are who they say they are.
I'd suggest storing the access_token on the server with the expires_in.
(I haven't dealt with refresh token's yet)
Code to validate tokens using the above libraries:
function validateTokenFacebook($token, $id=null) {
// Performed above
// FacebookSession::setDefaultApplication($config->fb->app_id, $config->fb->secret);
$session = new FacebookSession($token);
// Fetch user info
$request = new FacebookRequest($session, 'GET', '/me');
try {
$response = $request->execute();
} catch (\Facebook\FacebookServerException $e) {
$this->mlog->err($e . "\n" . $e->getTraceAsString());
throw new AuthTokenInvalidException();
}
$graphObject = $response->getGraphObject();
$user_id = $graphObject->getProperty('id');
return array(access_token, $user_id);
}
function validateTokenGoogle($token, $id=null) {
$resp=array();
// This key isn't included in the token from hello.js, but
// google needs it
if (!array_key_exists('created', $token)) $token['created'] = $token['expires'] - $token['expires_in'];
$client = new \Google_Client();
$client->setClientId($this->systemConfig->google->app_id);
$client->setClientSecret($this->systemConfig->google->secret);
$client->setRedirectUri($this->systemConfig->google->redirectUri);
$client->setScopes('email');
$client->setAccessToken(json_encode($token));
try {
// Send Client Request
$objOAuthService = new \Google_Service_Oauth2($client);
$userData = $objOAuthService->userinfo->get();
return array($token['access_token'], $userData['id']);
} catch (\Google_Auth_Exception $e) {
throw new AuthException('Google returned ' . get_class($e));
}
}
function validateTokenSoundcloud($token, $id=null) {
$soundcloud = new \Soundcloud\Service(
$this->systemConfig->soundcloud->app_id,
$this->systemConfig->soundcloud->secret,
$this->systemConfig->soundcloud->redirect);
$soundcloud->setAccessToken($access_token);
try {
$response = json_decode($soundcloud->get('me'), true);
if (array_key_exists('id', $response))
return array($access_token, $response['id']);
} catch (Soundcloud\Exception\InvalidHttpResponseCodeException $e) {
$this->mlog->err($e->getMessage());
}
throw new AuthTokenInvalidException();
}
I have a few custom classes above, such as the Exceptions and the systemConfig, but I think it's verbose enough to communicate what they do.