Google API PHP - listing groups of an user - php

i am struggling with google API. I am creating a website where I would like to read the groups of which the authenticated user is a member.
I have read everything about the subject, but many examples are very old and in the meantime things have changed.
This is the code I'm testing:
<?php
require 'lib/google-api/vendor/autoload.php';
// Creating new google client instance
$client = new Google_Client();
// Enter your Client ID
$client->setClientId('***.apps.googleusercontent.com');
// Enter your Client Secrect
$client->setClientSecret('***');
// Enter the Redirect URL
$client->setRedirectUri('***');
$client->setApplicationName("Test");
// Adding those scopes which we want to get (email & profile Information)
$client->addScope("email");
$client->addScope("profile");
$client->addScope("https://www.googleapis.com/auth/admin.directory.group.readonly");
$client->addScope("https://www.googleapis.com/auth/admin.directory.group.member.readonly");
if(isset($_GET['code'])){
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
if(!isset($token["error"])){
$client->setAccessToken($token['access_token']);
// getting profile information
$google_oauth = new Google_Service_Oauth2($client);
$google_account_info = $google_oauth->userinfo->get();
// Storing data into database
$email = $google_account_info->email;
$full_name = $google_account_info->name;
echo $email . "<br>";
// this is needed only if you need to perform
// domain-wide admin actions, and this must be
// an admin account on the domain; it is not
// necessary in your example but provided for others
$client->setSubject('***');
// set the authorization configuration using the 2.0 style
$client->setAuthConfig("***.json");
$adminService = new Google_Service_Directory($client);
$googleGroups = $adminService->groups->listGroups(array('domain'=>'mydomain.com'));
$groups = $googleGroups->getGroups();
}
}
?>
I am getting the following error
Uncaught Google_Service_Exception: {
"error": "unauthorized_client",
"error_description": "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
}
I have already done a Google Workspace Domain-Wide Delegation of Authority (https://developers.google.com/admin-sdk/directory/v1/guides/delegation) and I created a user to impersonate with read permissions on groups and users.
Where am I doing wrong? Thank you!

After some testing I made it work...
First of all i needed to give rights to the service account, not just at the one to impersonate.
$client = new Google_Client();
// Client ID
$client->setClientId(***);
// Client Secrect
$client->setClientSecret(***);
// Redirect URL
$client->setRedirectUri('https://www.mywebsite.com');
$client->setApplicationName('App name');
// Scopes for group reading, profile and email info
$client->addScope('https://www.googleapis.com/auth/admin.directory.group.readonly');
$client->addScope('https://www.googleapis.com/auth/userinfo.email');
$client->addScope('https://www.googleapis.com/auth/userinfo.profile');
if(isset($_GET['code'])){
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
if(!isset($token["error"])){
$client->setAccessToken($token['access_token']);
$google_oauth = new Google_Service_Oauth2($client);
// User info
$google_account_info = $google_oauth->userinfo->get();
$email = $google_account_info->email;
// Service account info
$client->setAuthConfig('***.json');
// Who i want to impersonate
$client->setSubject('admin#website.com');
$service = new Google_Service_Directory($client);
// Search groups of the logged user
$optParams = array(
'domain' => 'mywebsite.com',
'userKey' => $email
);
$googleGroups = $service->groups->listGroups($optParams);
$groups = $googleGroups->getGroups();
That's all :)

Related

Refresh token on Google OAuth2 PHP library

I implemented Google OAuth2 for user login on my website.
It works but after 1 hour token expires and login fails.
I read on the web that I need to get the Refresh Token (for Facebook Login I used a Long Lived Token), but code I tried doesn't work.
Here the code:
//LOGIN CALLBACK FROM GOOGLE
$gClient = new Google_Client();
$gClient->setApplicationName(SITE_TITLE);
$gClient->setClientId(get_option('google_api_id')->value);
$gClient->setClientSecret(get_option('google_api_secret')->value);
$gClient->addScope('profile');
$gClient->addScope('email');
$gClient->setRedirectUri(SITE_URL."/login/google/google-callback.php");
if(isset($_GET['code'])) {
$gClient->setAccessType('offline');
$token = $gClient->fetchAccessTokenWithAuthCode($_GET['code']);
$gClient->setAccessToken($token['access_token']);
$_SESSION['google_access_token'] = $token['access_token'];
}
if($gClient->getAccessToken()) {
// Get user profile data from google
$google_oauthV2 = new Google_Service_Oauth2($gClient);
$gpUserProfile = $google_oauthV2->userinfo->get();
}
...
This first snippet works fine.
In this second snipped, when user change page, I verify if login is still active:
$gClient = new Google_Client();
$gClient->setApplicationName(SITE_TITLE);
$gClient->setClientId(get_option('google_api_id')->value);
$gClient->setClientSecret(get_option('google_api_secret')->value);
$gClient->addScope('profile');
$gClient->addScope('email');
$gClient->setAccessType('offline');
$gClient->setAccessToken($_SESSION['google_access_token']);
if($gClient->getAccessToken()) {
if ($gClient->isAccessTokenExpired()) {
$gClient->fetchAccessTokenWithRefreshToken($gClient->getRefreshToken());
}
$google_oauthV2 = new Google_Service_Oauth2($gClient);
$gpUserProfile = $google_oauthV2->userinfo->get();
...
}
This second snipped doesn't work, because method fetchAccessTokenWithRefreshToken($gClient->getRefreshToken()) fails because $gClient->getRefreshToken() is NULL.
I debugged the callback and I saw that $token = $gClient->fetchAccessTokenWithAuthCode returns an array without "refresh_token" field.
Can anyone help me?
Thanks
Bye

Cannot use object of type Google_Auth_LoginTicket as array

I was performing Google Sign in on Android Application for the first time. At the client side, I obtained the access token and sent to the PHP server via POST.
By referring to Google's Documentation, the code I used in backend is as follows:
$id_token = $_POST['id_token'];
$CLIENT_ID = "** MY WEB APPLICATION CLIENT ID **";
$client = new Google_Client(['client_id' => $CLIENT_ID]);
$client->setAuthConfigFile('client_secret.json');
...
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
} else {
echo "Invalid Token";
}
When obtaining user id, the error is : "Cannot use object of type Google_Auth_LoginTicket as array"
I am pretty new to Google sign in. Please point out what all has gone wrong.
Found It. I made some modifications to the code
$token_data = $client->verifyIdToken($id_token)->getAttributes();
$user_id = $token_data['payload']['sub'];
Now the user id is retrieved fine.

Google Admin SDK PHP cannot create user. Not Authorized

I'm having a problem implementing Google Admin SDK in PHP. It always give error
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling POST
https://www.googleapis.com/admin/directory/v1/users: (403) Not Authorized to access this
resource/api' in ..\google-api-php-client\src\Google\Http\REST.php on line 79
Here is my code :
<?php
session_start();
/* * **********************************************
Make an API request authenticated with a service
account.
* ********************************************** */
set_include_path("google-api-php-client/src" . PATH_SEPARATOR . get_include_path());
require_once 'Google/Client.php';
require_once 'Google/Service/Directory.php';
/* * **********************************************
ATTENTION: Fill in these values! You can get
them by creating a new Service Account in the
API console. Be sure to store the key file
somewhere you can get to it - though in real
operations you'd want to make sure it wasn't
accessible from the webserver!
The name is the email address value provided
as part of the service account (not your
address!)
Make sure the Books API is enabled on this
account as well, or the call will fail.
* ********************************************** */
$client_id = 'my_client_id'; //Client ID
$service_account_name = 'email'; //Email Address
$key_file_location = 'key.p12'; //key.p12
if ($client_id == '<YOUR_CLIENT_ID>' || !strlen($service_account_name) || !strlen($key_file_location)) {
echo missingServiceAccountDetailsWarning();
}
$client = new Google_Client();
$client->setApplicationName("appname");
$service = new Google_Service_Directory($client);
/* * **********************************************
If we have an access token, we can carry on.
Otherwise, we'll get one with the help of an
assertion credential. In other examples the list
of scopes was managed by the Client, but here
we have to list them manually. We also supply
the service account
* ********************************************** */
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name, array('https://www.googleapis.com/auth/admin.directory.user'), $key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
/* * **********************************************
We're just going to make the same call as in the
simple query as an example.
* ********************************************** */
$familyName = filter_input(INPUT_GET, 'familyname');
$givenName = filter_input(INPUT_GET, 'givenname');
$password = filter_input(INPUT_GET, 'password');
$primaryEmail = filter_input(INPUT_GET, 'email');
$user = new Google_Service_Directory_User();
$name = new Google_Service_Directory_UserName();
$name->setFamilyName($familyName);
$name->setGivenName($givenName);
$user->setName($name);
$user->setHashFunction("MD5");
$user->setPrimaryEmail($primaryEmail);
$user->setPassword(hash("md5", $password));
$result = $service->users->insert($user);
There is no documentation and I'm very confused with this error.
I had a similar problem until I set the "sub" account on the credentials object which is the email address for the administrative user that you want to perform the API action as.
So in Google Apps Admin for your domain I assume you've created a user and added them to and admin role that has API access to users right? In your code above you just need to add (with correct email address of course):
$cred->sub = "adminuser#domain.com";
Add that right before:
$client->setAssertionCredentials($cred);
I did a full example for someone else that you might be able to reference too: https://gist.github.com/fillup/9fbf5ff35b337b27762a
I had a similar problem but found a solution to this by going through this blog
http://michaelseiler.net/2014/12/16/google-admin-sdk-api-with-php/
Assuming you have done all the necessary setting up on the Admin Console (i.e. delegating domain authority), then pay particular attention to the line
`$cred = new Google_Auth_AssertionCredentials($service_account_name, array('https://www.googleapis.com/auth/admin.directory.user'), $key);`
this should be:
`$user_to_impersonate = 'adminaccount#example.com';$scopes =array('https://www.googleapis.com/auth/admin.directory.user');$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
$scopes,
$key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate);`
I changed that and boom....
I think i was receiving this error when i tried to query a user.
During the creation of the JWT_CLAIM portion of the assertion, you must specify a domain admin account that your service account can impersonate... this part was poorly documented, i thought.
i dont know exactly how the google php library does it, but i didnt see anywhere in your code where you specify that account email address. if you have looked at the oauth2 documentation, in the jwt_claim secion, there is an "additional claims" subsection that says:
To obtain an access token that grants an application delegated access to a resource, include the email address of the user in the JWT claim set as the value of the sub field.
I had to include that admin email account in the creation of my assertion before i could even query the directory.users API.
i apologize if this isnt helpful, but im not using the library for php, im building my own (with php).

Writing a twitter API using php that is username specific

I've written a twitter api application using the following tutorial:
http://www.youtube.com/watch?v=GQaPt-gQVRI
How can I modify the script to generate a timeline stream that is specific to a user so that the application when run will show user's timeline stream and not mine (since i wrote the app and therefore it has my twitter credentials)
Thanks
the php application validates my twitter credentials using the following:
<?php
require 'tmhOAuth.php'; // Get it from: https://github.com/themattharris/tmhOAuth
// Use the data from http://dev.twitter.com/apps to fill out this info
// notice the slight name difference in the last two items)
$connection = new tmhOAuth(array(
'consumer_key' => 'my key',
'consumer_secret' => 'my secret',
'user_token' => 'my token', //access token
'user_secret' => 'my user secret' //access token secret
));
// set up parameters to pass
$parameters = array();
if ($_GET['count']) {
$parameters['count'] = strip_tags($_GET['count']);
}
if ($_GET['screen_name']) {
$parameters['screen_name'] = strip_tags($_GET['screen_name']);
}
if ($_GET['twitter_path']) { $twitter_path = $_GET['twitter_path']; } else {
$twitter_path = '1.1/statuses/user_timeline.json';
}
$http_code = $connection->request('GET', $connection->url($twitter_path), $parameters );
if ($http_code === 200) { // if everything's good
$response = strip_tags($connection->response['response']);
if ($_GET['callback']) { // if we ask for a jsonp callback function
echo $_GET['callback'],'(', $response,');';
} else {
echo $response;
}
} else {
echo "Error ID: ",$http_code, "<br>\n";
echo "Error: ",$connection->response['error'], "<br>\n";
So without having to pass a new username in the api call, how can i add a snippet to require the user to log in? and if i add that snippet for the user to log in, will the api automatically populate the authentication strings with the user's?
You can send a get request to the following url to get a users timeline.
https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi&count=2
You can replace the parameters screen_name with the username you want to access, and you can replace count with the number of tweets you would like to get, count is optional and doesn't have to be included.
You can read more about statuses/user_timeline on the office twitter API site: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
If you wish to get a user to sign in then your best bet would be to use the twitteroauth library by abraham
Download and include in your project, then include the library and start a session.
require("twitteroauth/twitteroauth.php");
session_start();
Then create a new instance and authenticate with your app details. You can set a url to redirect to when the user authenticates. You also need to cache your tokens.
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET');
$request_token = $twitteroauth->getRequestToken('http://example.com/loggedin.php');
$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
Redirect the user to twitter to authenticate
header('Location: '.$twitteroauth->getAuthorizeURL($request_token['oauth_token']));
In the file that you set twitter to redirect to you need to re-authenticate using the tokens created. Twitter will also add a parameter to your url which you use to create a access token for that user. Now when you send GET requests to twitter, it does it on behalf of the user logged in.
require("twitteroauth/twitteroauth.php");
session_start();
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
$user_info = $twitteroauth->get('account/verify_credentials');
print_r($user_info);
You can get additional details from $user_info which you can cache or store in a database, which will allow you to remember users that have already authenticated. You will need to use oauth_token and oauth_secret, something like this.
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', 'OAUTH_TOKEN', 'OAUTH_SECRET');

PHP/Twitter oAuth - Automated Tweets

Im using the following code to read to consumer_key and consumer_secret from config.php, pass it to twitter and retrieve some bits of information back from them.
What the script below attempts to do is 'cache' the request_token and request_secret. So in theory I should be able to reuse those details (all 4 of them to automatically tweet when required).
<?php
require_once('twitteroauth/twitteroauth.php');
require_once('config.php');
$consumer_key = CONSUMER_KEY;
$consumer_secret = CONSUMER_SECRET;
if (isset($_GET["register"]))
{
// If the "register" parameter is set we create a new TwitterOAuth object
// and request a token
/* Build TwitterOAuth object with client credentials. */
$oauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
$request = $oauth->getRequestToken();
$request_token = $request["oauth_token"];
$request_token_secret = $request["oauth_token_secret"];
// At this I store the two request tokens somewhere.
file_put_contents("request_token", $request_token);
file_put_contents("request_token_secret", $request_token_secret);
// Generate a request link and output it
$request_link = $oauth->getAuthorizeURL($request);
echo "Request here: " . $request_link . "";
die();
}
elseif (isset($_GET["validate"]))
{
// This is the validation part. I read the stored request
// tokens.
$request_token = file_get_contents("request_token");
$request_token_secret = file_get_contents("request_token_secret");
// Initiate a new TwitterOAuth object. This time we provide them with more details:
// The request token and the request token secret
$oauth = new TwitterOAuth($consumer_key, $consumer_secret,
$request_token, $request_token_secret);
// Ask Twitter for an access token (and an access token secret)
$request = $oauth->getAccessToken();
// There we go
$access_token = $request['oauth_token'];
$access_token_secret = $request['oauth_token_secret'];
// Now store the two tokens into another file (or database or whatever):
file_put_contents("access_token", $access_token);
file_put_contents("access_token_secret", $access_token_secret);
// Great! Now we've got the access tokens stored.
// Let's verify credentials and output the username.
// Note that this time we're passing TwitterOAuth the access tokens.
$oauth = new TwitterOAuth($consumer_key, $consumer_secret,
$access_token, $access_token_secret);
// Send an API request to verify credentials
$credentials = $oauth->oAuthRequest('https://twitter.com/account/verify_credentials.xml', 'GET', array());
// Parse the result (assuming you've got simplexml installed)
$credentials = simplexml_load_string($credentials);
var_dump($credentials);
// And finaly output some text
echo "Access token saved! Authorized as #" . $credentials->screen_name;
die();
}
?>
When i run /?verify&oauth_token=0000000000000000 - It works however trying to resuse the generated tokens etc... I get a 401
Here is the last bit of code where I attempt to reuse the details from Twitter combined with my consumer_key and consumer_secret and get the 401:
require_once('twitteroauth/twitteroauth.php');
require_once('config.php');
// Read the access tokens
$access_token = file_get_contents("access_token");
$access_token_secret = file_get_contents("access_token_secret");
// Initiate a TwitterOAuth using those access tokens
$oauth = new TwitterOAuth($consumer_key, $consumer_key_secret,
$access_token, $access_token_secret);
// Post an update to Twitter via your application:
$oauth->OAuthRequest('https://twitter.com/statuses/update.xml',
array('status' => "Hey! I'm posting via #OAuth!"), 'POST');
Not sure whats going wrong, are you able to cache the details or do i need to try something else?
You can't store the OAuth tokens in cache and to more than 1 request with it, as OAuth is there to help make the system secure, your "oauth_token" will contain some unique data, this token will only be able to make one call back to twitter, as soon as the call was made, that "oauth_token" is no longer valid, and the OAuth class should request a new "oauth_token", thus making sure that every call that was made is secure.
That is why you are getting an "401 unauthorized" error on the second time as the token is no longer valid.
twitter is still using OAuth v1 (v2 is still in the draft process even though facebook and google already implemented it in some parts)
The image below describes the flow of the OAuth authentication.
Hope it helps.
A while ago I used this to connect to twitter and send tweets, just note that it did make use of some Zend classes as the project was running on a zend server.
require_once 'Zend/Service/Twitter.php';
class Twitter {
protected $_username = '<your_twitter_username>';
protected $_token = '<your_twitter_access_token>';
protected $_secret = '<your_twitter_access_token_secret>';
protected $_twitter = NULL;
//class constructor
public function __construct() {
$this->getTwitter();
}
//singleton twitter object
protected function getTwitter() {
if (null === $this->_twitter) {
$accessToken = new Zend_Oauth_Token_Access;
$accessToken->setToken($this->_token)
->setTokenSecret($this->_secret);
$this->_twitter = new Zend_Service_Twitter(array(
'username' => $this->_username,
'accessToken' => $accessToken,
));
$response = $this->_twitter->account->verifyCredentials();
if ($response->isError()) {
throw new Zend_Exception('Provided credentials for Twitter log writer are wrong');
}
}
return $this->_twitter;
}
//send a status message to twitter
public function update( $tweet ) {
$this->getTwitter()->status->update($tweet);
}
}
In your second script, it looks like you aren't setting the Consumer Key and Consumer Secret when you create your TwitterOAuth instance.
// Initiate a TwitterOAuth using those access tokens
$oauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token, $access_token_secret);

Categories