PHP Google Adwords: invalid_grant - php

I have made a request to google adwords and got a refresh token (without using GetRefreshToken.php from the php library). I have copied and pasted the refresh_token, developerToken, client_id and client_secret into the auth.ini file.
But when I run the following part:
$user = new AdWordsUser();
$campaignService = $user->GetService('CampaignService', 'v201603');
// Create selector.
$selector = new Selector();
$selector->fields = array('Id', 'Name');
$selector->ordering[] = new OrderBy('Name', 'ASCENDING');
// Create paging controls.
$selector->paging = new Paging(0, AdWordsConstants::RECOMMENDED_PAGE_SIZE);
// Make the get request.
$page = $campaignService->get($selector);
In return I get the following error:
OAuth2Exception in SimpleOAuth2Handler.php line 119:
{
"error" : "invalid_grant"
}
The library is: Library. And the SimpleOAuth2Handler.php is here: Oauth
Any ideas why?

Have you tried passing the values directly into the adwords constructor function to make sure they are valid or at least are you setting the customer account number ? . The refresh token is used to obtain an access token which is good for about an hour. Caching this would help performance as you would not need to fetch a new access token every request.
Try adding the following -
$user->SetClientCustomerId('set your account number here');
// also if you are sure your oAuth data is valid
$user->SetOAuth2Info('pass your oauth data')

Related

Fat Free Use Google OAuth + Google API

I'm trying the following thing for quite a while now and am heavily struggling...
On a website, I first want to authenticate a user with his Google Account using OAuth. Therefore, I'm using this library. In order to get it working, I used $f3->set('AUTOLOAD','vendor/ikkez/f3-opauth/lib/opauth/'); to load the PHP files and then used the following code to create the routes and make the authentication possible:
$f3 = \Base::instance();
// load opauth config (allow token resolve)
$f3->config('vendor/ikkez/f3-opauth/lib/opauth/opauth.ini', TRUE);
// init with config
$opauth = OpauthBridge::instance($f3->opauth);
// define login handler
$opauth->onSuccess(function($data){
header('Content-Type: text');
//$data['credentials']['token'];
});
// define error handler
$opauth->onAbort(function($data){
header('Content-Type: text');
echo 'Auth request was canceled.'."\n";
print_r($data);
});
So far so good, thats all working fine, once permission is granted from Google I get the correct callback, also including the login token.
Now the next step is, that after user gave permission for that (by authenticating), I want to check, if the user subscribed to a specific channel on Youtube (and afterwards saving that information to my DB, printing it at the first step would be enough though).
Now I did my homework for multiple hours in trying to figuring out how it works...
What I (in general found) is that the following curl request should give me the desired result:
curl \
'https://youtube.googleapis.com/youtube/v3/subscriptions?part=snippet%2CcontentDetails&forChannelId=UC_x5XG1OV2P6uZZ5FSM9Ttw&mine=true&key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--compressed
I then tried to sent this curl request with PHP, substituting the API KEY with my Google API Key and "YOUR_ACCESS_TOKEN" with the token I got from OAUTH.... However, it's throwing an error, saying "request had insufficient authentication scopes"... That seems to be because when checking the PHP example from Google, I have to provide the Scopes I'm using - in my case https://www.googleapis.com/auth/youtube.readonly.
The PHP code provided by Google is the following:
<?php
/**
* Sample PHP code for youtube.subscriptions.list
* See instructions for running these code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#php
*/
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
throw new Exception(sprintf('Please run "composer require google/apiclient:~2.0" in "%s"', __DIR__));
}
require_once __DIR__ . '/vendor/autoload.php';
$client = new Google_Client();
$client->setApplicationName('API code samples');
$client->setScopes([
'https://www.googleapis.com/auth/youtube.readonly',
]);
// TODO: For this request to work, you must replace
// "YOUR_CLIENT_SECRET_FILE.json" with a pointer to your
// client_secret.json file. For more information, see
// https://cloud.google.com/iam/docs/creating-managing-service-account-keys
$client->setAuthConfig('YOUR_CLIENT_SECRET_FILE.json');
$client->setAccessType('offline');
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open this link in your browser:\n%s\n", $authUrl);
print('Enter verification code: ');
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Define service object for making API requests.
$service = new Google_Service_YouTube($client);
$queryParams = [
'forChannelId' => 'UC_x5XG1OV2P6uZZ5FSM9Ttw',
'mine' => true
];
$response = $service->subscriptions->listSubscriptions('snippet,contentDetails', $queryParams);
print_r($response);
This let's me run into a new issue... Trying to use this code, I'm getting the error, that Google_Client is not known as class... I then went ahead and installed Google Client with Composer and tried to use vendor/autoload.php in order to use the class.... However, when including the autoload.php, I get the error Fatal error: Cannot declare class Prefab, because the name is already in use... This seems to be the case, because the f3-opauth declares this Prefab class already and then the google apiclient tries to declare it again... However, I didn't manage to to include google apiclient without the autoload...
You see, I really tried a lot and I've been working on this for about 5-6 hours today, only getting that one API request to work and I don't know what else to try...
Any hint on how to get it working would be appreciated - if there's any hint on doing it a completely other way, I'd be willing to change it as well, as the project itself just started.
Summarizing, what I'm trying to do is the following:
-> User can log in on Website with his Youtube/Google Account
-> When authenticating, its checked, if the User is a Subscriber of a specific channel. Next step would be to also check, if he is a channel member of this speicific channel. Both information would need to be saved to database
-> after that, user can always log in into his account with Google again and in the database, you can find the information if the user is subscriber and/or channel member of this channel..
Thanks in advance!
I'm not sure if this will help with your exact use case, but I've worked with Google APIs in the past with Fat-Free. I couldn't get it to work right off the bat, so I installed and got it working with the Google Client/API/SDK. Once I got that working, then I worked backwards to see if I could make it work with Fat-Free. One of the things that I noticed I was running into was missing fields in the Oauth request. access_type was one that got me as well as approval_prompt. I know that you said you've gotten your access token thus far, so it may not apply, but it could for future requests. Here's some example code I've got working to generate an oauth URL for Google Sign in, and then to process the request and make the call to the userinfo portion.
<?php
class App_Auth {
public static function generateOauthUrl() {
$fw = Base::instance();
$Oauth = new \Web\OAuth2();
$Oauth->set('client_id', $fw->get('google.client_id'));
$Oauth->set('scope', 'profile email');
$Oauth->set('response_type', 'code');
$Oauth->set('access_type', 'online');
$Oauth->set('approval_prompt', 'auto');
$Oauth->set('redirect_uri', $fw->SCHEME.'://' . $_SERVER['HTTP_HOST'] . $fw->BASE.'/oauthRedirect');
return $Oauth->uri('https://accounts.google.com/o/oauth2/auth', true);
}
public static function processAuthCodeAndGetToken($auth_code) {
$fw = Base::instance();
$Oauth = new \Web\OAuth2();
$Oauth->set('client_id', $fw->get('google.client_id'));
$Oauth->set('client_secret', $fw->get('google.client_secret'));
$Oauth->set('scope', 'profile email');
$Oauth->set('access_type', 'online');
$Oauth->set('grant_type', 'authorization_code');
$Oauth->set('code', $auth_code);
$Oauth->set('approval_prompt', 'auto');
$Oauth->set('redirect_uri', $fw->SCHEME.'://' . $_SERVER['HTTP_HOST'] . $fw->BASE.'/oauthRedirect');
return $Oauth->request('https://oauth2.googleapis.com/token', 'POST');
}
public static function getOauthUserInfo($access_token) {
$Oauth_User_Info = new \Web\OAuth2();
return $Oauth_User_Info->request('https://www.googleapis.com/oauth2/v2/userinfo', 'GET', $access_token);
}
One other error that has bitten me in the backside was we would get our access token from Google and then store it in the database for subsequent requests. We would get that scopes error you mentioned request had insufficient authentication scopes. We eventually figured out that the access_token was longer than our database field (VARCHAR(32) if I remember right) so we needed to make our database field longer so it would store the whole thing.
Hopefully one of those triggers something for you to figure out your issue.

401 Invalid credentials when trying to reach the Google Search Console API in PHP

I'm trying to set up the Google Search Console API in Laravel and I'm struggling with getting it working with my newly-generated credentials. I've set up an API key in the console and inserted this into my code, however upon trying to fetch the data the application returns 401 Invalid credentials. I feel really stupid for not being able to get this working since I would assume copying the API key and inserting it in my code would do the job. Which key is required to authenticate and retrieve data from the Search Console API?
I have tried setting up a new API key and using that key in the setAccessToken field. I even tried setting up Oauth 2.0 and using those credentials to authenticate. It seems the program crashes at 'setAccessToken'. The only other key I applied is the developer key ($client->setDeveloperKey())
public static function debugSiteData() {
// Dates (YYYY-mm-DD)
$fromDate = date('Y-m-d', strtotime('-3 months'));
$toDate = date('Y-m-d', strtotime('-1 day'));
$client = new Google_Client();
$client->setApplicationName("application_name");
$client->setDeveloperKey('AIza(...)');
$client->addScope(Google_Service_Webmasters::WEBMASTERS_READONLY);
$webmaster = new Google_Service_Webmasters($client);
$searchConsole = new SearchConsoleClient($client);
$searchConsole->setAccessToken("ACCESS TOKEN");
// $debugData = var_export($searchConsole);
$search = new \Google_Service_Webmasters_SearchAnalyticsQueryRequest();
$search->setStartDate($fromDate);
$search->setEndDate($toDate);
$console = $webmaster->urlcrawlerrorscounts->query('http://www.website.com/', array())->getCountPerTypes();
return '<pre>' . $console . '</pre>';
}
With the method above I'm getting a 401 Invalid credentials error. I feel like it's something really simple but I can't seem to figure it out at this point.
Using Oauth is a good idea to trigger Google APIs, in your case, you need to store the credentials in your DB after Oauth callback, access_token, refresh_token, expires_in, then you need to use those credentials to use the Google API's
$client = new Google_Client();
// Set Client Id (From Google Cloud Console)
$client->setClientId($client_id);
// Set Client Secret (From Google Cloud Console)
$client->setClientSecret($client_secret);
// Set Access Token With Oauth credentials (form DB)
$client->setAccessToken([
'access_token' => $token,
'refresh_token' => $refresh_token,
'expires_in' => $expires_in
]);
// Check if the access token is expired
if ($client->isAccessTokenExpired()) {
// This will refresh the token automatically
$token = $client->refreshToken(null);
$this->setAccessToken($token);
}

Graph User id property returning blank string

I've got a php web app (hosted on Azure) using the microsoft/microsoft-graph SDK for one of my authentication providers.
I am able to get a token and pull some of the user properties, but the 'id' value seems to be returning a blank string:
$me = $provider->get("me", $token);
printf('<br>Hello %s!', $me['displayName']);
printf('<br>First Name: %s', $me['givenName']);
printf('<br>Last Name: %s', $me['surname']);
printf('<br>ID: %s', $me['id']); // returns nothing
printf('<br>Email: %s', $me['userPrincipalName']);
printf('<br>Country: %s', $me['country']);
printf('<br>Postal Code: %s', $me['postalCode']);
According to the User reference, I should be able to get the user ID value as a string.
I am also using thenetworg/oauth2-azure as part of the project and the following does return a GUID. Is it the same ID that I'm looking for? The unique user ID from Graph? Or is it a different ID?
printf('<br>ID: %s', $resourceOwner->getId());
Ideally, I'd like to get the ID value directly from Graph like all the other properties. Is there something I'm missing that I need to do special for the ID property? (well, obviously...) Is the issue with Graph, with the php library, or something else?
Thanks for your assistance.
[Update]
OK, so backing up a step: I've got two pages:
Page 1 has links to a number of authentication options.
Page 2 is a redirect from one of those options - the Microsoft Work and School option.
Page 1 now uses the following to create the link:
$mscallbackUrl = $urlcore . '/ms-callback.php';
$provider = new TheNetworg\OAuth2\Client\Provider\Azure([
'clientId' => $msAppId,
'clentSecret' => $msAppSecret,
'redirectUri' => $mscallbackUrl
]);
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
$authUrl = $provider->getAuthorizationUrl();
Page 2 uses the exact same code above to set up $provider then uses the following to connect to Graph:
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
try {
$graph = new \Microsoft\Graph\Graph();
$graph->setAccessToken($token->getToken());
$me = $graph->createRequest("GET", "/me")
->setReturnType(Model\User::class)
->execute();
printf('<br>Hello %s!', $me->getDisplayName());
printf('<br>ID: %s', $me->id);
This code is failing on $me = $graph->createRequest
One reference I found said it could be failing because of an issue with the token.
I think there are a few things that may be causing the confusion. By default, the oauth2-azure library authenticates for the AAD Graph resource (https://graph.windows.net) instead of the Microsoft Graph resource (https://graph.microsoft.com), so you will want to verify that you request an access token for the correct resource.
Secondly, AAD Graph does not return an id field so this will return null. I believe the correlated equivalent field to MS Graph is oid.
Third, you are using the oauth2-azure library to access AAD Graph instead of the microsoft-graph library for Microsoft Graph. Once you get your access token, you can pass that into a new Graph instance like so:
$graph = new \Microsoft\Graph\Graph();
$graph->setAccessToken($token->getToken());
$me = $graph->createRequest("GET", "/me")
->setReturnType(Model\User::class)
->execute();
echo $me->id;

Spotify Web API - Client Credentials - Accessing a users playlists

I'm trying to access users playlist tracks by using the client credentials flow.
Spotify getting playlist documentation: https://developer.spotify.com/web-api/get-playlists-tracks/
Spotify getting client credentials documentation: https://developer.spotify.com/web-api/authorization-guide/
First question, is it possible to get a users playlist tracks using client credentials flow? I'm using this flow since I'm unable to pop up a login box for the user to login.
Secondly, I've tried using https://github.com/jwilsson/spotify-web-api-php client credentials flow (Docs: http://jwilsson.github.io/spotify-web-api-php/authorization.html) by practically copying the code at the bottom of that page:
<?php
include('vendor/autoload.php');
$session = new SpotifyWebAPI\Session('Tobys client id', 'Tobys secret', 'http://localhost/callback');
// Request a access token with optional scopes
$scopes = array(
'playlist-read-private',
'user-read-private'
);
$session->requestCredentialsToken($scopes);
$accessToken = $session->getAccessToken(); // We're good to go!
// Set the code on the API wrapper
$api->setAccessToken($accessToken);
$playlists = $api->getUserPlaylists('USER_ID', array(
'limit' => 5
));
foreach ($playlists->items as $playlist) {
echo '' . $playlist->name . ' <br>';
}
This gives me Notice: Undefined variable: api in /var/www/html/dev/testing.php on line 16
I've also tried creating the API variable using $api = new SpotifyWebAPI\SpotifyWebAPI(); but this says I need user information/ tokens.
Thanks.
First question, is it possible to get a users playlist tracks using
client credentials flow?
Yes, retrieving tracks for a playlist doesn't require user authentication as part of the access token.
I've also tried creating the API variable using $api = new
SpotifyWebAPI\SpotifyWebAPI(); but this says I need user information/
tokens.
Looking at the code (Session class, SpotifyWebapi class), it does look like you should set this up by doing
$api = new SpotifyWebAPI\SpotifyWebAPI();
$session = new SpotifyWebAPI\Session($clientId, $clientSecret, $redirectUri);
$api->setAccessToken($session->getAccessToken());
When that's set up you should be good to use the getUserPlaylists method like you're doing in your example code.

How to get data from facebook Ads on the Graph API?

I am new to PHP and facebook API'S
I am trying to get data from my ads account on faceobook using PHP
I just want to know how much $ every ads spent
First of all - I did not understand if I must have facebook app in order to get data from my personal ad account ?
I assumed yes so I created one now..,
I am geting the acess token like this :
require_once("facebook.php");
$config = array();
$config['appId'] = 'myapp_id';
$config['secret'] = 'myappsecret';
$config['fileUpload'] = false; // optional
$facebook = new Facebook($config);
// Set a new app secret
$facebook->setApiSecret($config['secret']);
// If you do above, also set the app id
$facebook->setAppId( $config['appId']);
$access_token = $facebook->getAccessToken();
But when I am trying a get request like this:
https://graph.facebook.com/act_[my_account_number]/adgroups
I am getting a premisson exception that tell me
An access token is required to request his resource
But where do I put the access token ?
You need to add it at the end of the url as a url parameter:
"https://graph.facebook.com/act_[my_account_number]/adgroups" . "?access_token=" . $access_token
However, from the code I think you are getting an App Access Token, and you need a Page Access Token or a User Access Token to get the ads related to your Facebook Page.
Please refer to https://developers.facebook.com/docs/facebook-login/access-tokens/ for more information.

Categories