Google Admin 403 Error with PHP - google-admin-sdk

I have been searching and trying many different solutions to this error that I have found not only this site but others as well.
Currently I am trying to just get a list of users or a specific user details based on parameters set. In the long run I would like to create and modify users and groups.
I have images but am new to posting to this site and I am unable to publish them here. I can confirm the following:
I have enabled API for the domain
api_studentportal(at)domain.com is a super admin
The Admin SDK is enabled under the developers console
Under 'Manage API client access' I have added '474470900273-asrfjsg0m0ucsfadeit456sg518l1bqa.apps.googleusercontent.com' to 'admin.directory.group' and 'admin.directory.user'
My Code:
date_default_timezone_set('America/Los_Angeles');
session_start();
set_include_path(get_include_path() . PATH_SEPARATOR . 'google/composer/src');
require 'composer/vendor/autoload.php';
$keychain = json_decode(file_get_contents('Google.json'), true);
$service_account_name = $keychain['client_email']; //474470900273-asrfjsg0m0ucsfadeit456sg518l1bqa#developer.gserviceaccount.com
$private_key = $keychain['private_key'];
$client = new Google_Client();
$client->setApplicationName("SAMPLE");
$service = new Google_Service_Directory($client);
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/admin.directory.user', 'https://www.googleapis.com/auth/admin.directory.group'),
$private_key,
'notasecret',
'http://oauth.net/grant_type/jwt/1.0/bearer',
'api_studentportal#domain.com'
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
$service = new Google_Service_Directory($client);
// Print the first 10 users in the domain.
$optParams = array(
'domain' => 'domain.com',
'maxResults' => 10,
'orderBy' => 'familyName',
'viewType' => 'domain_public',
);
$results = $service->users->listUsers($optParams);
And then I get the following PHP error:
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling GET https://www.googleapis.com/admin/directory/v1/users?domain=domain.com&maxResults=10&orderBy=familyName&viewType=domain_public: (403) Not Authorized to access this resource/api' in google/composer/src/Google/Http/REST.php:110 Stack trace: #0 google/composer/src/Google/Http/REST.php(62): Google_Http_REST::decodeHttpResponse(Object(Google_Http_Request), Object(Google_Client)) #1 [internal function]: Google_Http_REST::doExecute(Object(Google_Client), Object(Google_Http_Request)) #2 google/composer/src/Google/Task/Runner.php(174): call_user_func_array(Array, Array) #3 google/composer/src/Google/Http/REST.php(46): Google_Task_Runner->run() #4 google/composer/src/Google/Client.php(593): Google_Http_REST::execute(Object(Google_Client), Object(Google_Http_Request)) #5 google/composer in google/composer/src/Google/Http/REST.php on line 110

It seems as if it was just the viewType optParam defined. 'viewType' => 'domain_public' is invalid. Once that was removed the query worked.

Related

Paws::CognitoIdp::GetUser returns "Invalid Access Token"

Summary:
I tried to obtain AWS Cognito User name (OAuth2 from Google) with Perl module Paws::CognitoIdp::GetUser but I failed the code:
my $GetUserResponse = $cognito_idp->GetUser(
AccessToken => 'MyTokenModelType',
);
with the error Invalid Access Token.
Environment
I am developing Web service with following environment:
AWS + EC2 + Ubuntu 20.04 + nginx 1.20.1 + Perl 5.30.0
Using Cognito with Google OAuth2.0
What I can do now
When you access my Web service, Sign In with Google button will appear. If you click it, you can run my Perl CGI script.
What I cannot do now
I want to obtain your Google user name and mail address, but I cannot.
What I did
I wrote the following code:
my $cognito_idp = Paws->service('CognitoIdp',
region => "ap-northeast-1",
max_attempts => 3,
);
my $GetUserResponse = $cognito_idp->GetUser(
AccessToken => 'MyTokenModelType',
);
my $uname = $GetUserResponse->Username;
Then...
When I access my Web service, it failed with the Software error:
Software error:
Invalid Access Token
Trace begun at /usr/local/share/perl/5.30.0/Paws/Net/JsonResponse.pm line 22
Paws::Net::JsonResponse::process('Paws::Net::JsonResponse=HASH(0x56495fb33d78)', 'Paws::CognitoIdp::GetUser=HASH(0x56495fb41fd0)', 'Paws::Net::APIResponse=HASH(0x56495fde6f38)') called at /usr/local/share/perl/5.30.0/Paws/Net/Caller.pm line 46
Paws::Net::Caller::caller_to_response('Paws::Net::Caller=HASH(0x56495da09a38)', 'Paws::CognitoIdp=HASH(0x56495e05da48)', 'Paws::CognitoIdp::GetUser=HASH(0x56495fb41fd0)', 'Paws::Net::APIResponse=HASH(0x56495fde6f38)') called at /usr/local/share/perl/5.30.0/Paws/Net/RetryCallerRole.pm line 19
Paws::Net::RetryCallerRole::do_call('Paws::Net::Caller=HASH(0x56495da09a38)', 'Paws::CognitoIdp=HASH(0x56495e05da48)', 'Paws::CognitoIdp::GetUser=HASH(0x56495fb41fd0)') called at /usr/local/share/perl/5.30.0/Paws/CognitoIdp.pm line 331
Paws::CognitoIdp::GetUser('Paws::CognitoIdp=HASH(0x56495e05da48)', 'AccessToken', 'MyTokenModelType') called at /DocumentRoot/index.cgi line 16
For help, please send mail to this site's webmaster, giving this error message and the time and date of the error.
Maybe...
I referred following to the documentation
Maybe 'MyTokenModelType' is just the placeholder and I should specify the correct code.
But I don't know how I can make it.
In addition, I want to know how can I obtain not only user name but also user email address.
(Additional Info 2021-11-12)
Thanks to the comment, I read the article:
How to generate access token for an AWS Cognito user?
and I hacked AWS CLI command but I have not got the answer yet.
I think I got to do $ aws connito-idp initiate-auth but I cannot find what arguments I should pass.
In the AWS => Cognito => Users and groups menu, I see the entry of a user of my Web app.
Username: google_??????????
Enabled: Enabled
Account status: EXTERNAL_PROVIDER
Email: (users_email)
I changed my code like this for the experiment to find what information my Web app has.
use Data::Dumper;
my $cognito_idp = Paws->service('CognitoIdp',
region => "ap-northeast-1",
max_attempts => 3,
);
# my $GetUserResponse = $cognito_idp->GetUser(
# AccessToken => 'MyTokenModelType',
# );
# my $uname = $GetUserResponse->Username;
print "Content-type: text/html\n\n\n";
print '<!DOCTYPE html>';
print '<html><pre>';
print Dumper $cognito_idp;
print '</pre></html>';
and I see the contents of $cognito_idp like this:
$VAR1 = bless( {
'_region_for_signature' => 'ap-northeast-1',
...
'credentials' => bless( {
...
'selected_provider' => bless( {
'expiration' => 1636712506,
'actual_creds' => {
'Type' => 'AWS-HMAC',
'SecretAccessKey' => '??????????????',
'Code' => 'Success',
'AccessKeyId' => '???????????????',
'LastUpdated' => '2021-11-12T03:54:16Z',
'Token' => '?????????????????????????????????????',
'Expiration' => '2021-11-12T10:21:46Z'
},
...
I hope I could get the information of the user from the data above.
My question is, how I can specify the MyTokenModelType value of the code:
my $GetUserResponse = $cognito_idp->GetUser(
AccessToken => 'MyTokenModelType',
);
Still I want your info.
Thanks again.

Laravel Socialite - Facebook extend/replace token with a one with more permissions

I'm using Laravel 5.4 and Socialite to allow the visitor of my site to log in.
Situation
I recently obtained the user_events permission cause I wanted to add some functionalities to my website.
Before this, some users got registered in my database along with their user token in the database. (token than includes the default permissions but not user_events)
I updated the SocialAuthController.php to reflect the new permission on the new created user and this is working great
return Socialite::driver('facebook')
->scopes(['public_profile', 'user_events'])
->redirect();
Problem
If a user is already registered in the database with his token, it is impossible to run this command $fb->get('me/events') since the token does not include the user_events permissions.
Questions
Is there a way to force a user to grab a new token with a new permission without having to remove him from the database ? ( I have data associated with users) ?
SocialAuthController
public function handleProviderCallback(SocialAccountService $service)
{
$user = $service->createOrGetUser(Socialite::driver('facebook')->user());
}
SocialeAccountService
public function createOrGetUser(ProviderUser $providerUser)
{
$account = SocialAccount::whereProvider('facebook')
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook',
'nickname' => $providerUser->getNickname(),
'avatar' => $providerUser->avatar_original,
'token' => $providerUser->token,
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}

having trouble sending facebook notification via ajax call to php

In my javascript I have a click event that triggers an ajax call to the php page where I send my notification from. I chose to do it this way because the documentation advises against using your app secret in any client side code, and the notifications parameters requires an access token that you can only get using the app secret.
The problem I'm having is that even though I'm logged in, $facebook->getUser() is returning 0 in php, so the api call I make afterwards to send the notification wont work. My user is already logged in via the client side code, so how do I get the message to the php that they're logged in so the notification can be sent.
//JS
$.ajax({
url : "http://xxxxxo/bn/notification.php",
type : 'POST',
data: {notify: notify },
success : function (result) {
console.log(result);
},
error : function () {
alert("error sending notification");
}
});//closes ajax
//PHP
<?php
require_once(dirname(__FILE__).'/php-sdk/facebook.php') ;
$APPLICATION_ID = '1402xxxxx7';
$APPLICATION_SECRET = 'ce71d6bbxxxxx5f55a';
$fb_app_url = "http://apps.facebook.com/myAPP";
$config = array();
$config['appId'] = $APP_ID;
$config['secret'] = $APP_SECRET;
$config['cookie'] = true;
$facebook = new Facebook($config) or die('Error is here!');
$facebook = new Facebook(array(
'appId' => $APP_ID,
'secret' => $APP_SECRET,
'fileUpload' => true
));
$notify = $_REQUEST['notify'];
$userid = $facebook->getUser();
/*IF WE HAVE A LOGGED IN USER AND THE 'NOTIFY' REQUEST VALUE, THEN SEND THE NOTIFICATION.
BUT MY USER ID IS 0. HOW DO I GET PHP TO RECOGNIZE ME AS LOGGED IN WITHOUT HAVING TO FORCE MY USER TO LOG IN VIA PHP AFTER THEY'VE ALREADY LOGGED IN CLIENT SIDE?*/
if($userid && $notify){
$token_url ="https://graph.facebook.com/oauth/access_token?" .
"client_id=" . $APP_ID .
"&client_secret=" . $APP_SECRET .
"&grant_type=client_credentials";
$app_token = file_get_contents($token_url);
$app_token = str_replace("access_token=", "", $app_token);
$data = array(
'href'=> 'https://apps.facebook.com/thebringernetwork/',
'access_token'=> $app_token,
'template'=> 'test'
);
$sendnotification = $facebook->api('/1622649653/notifications', 'post', $data);
}else{
//handle error
}
?>
The first thing I noticed is that you define your app id as $APPLICATION_ID but use it as $APP_ID (and the same goes for your app secret). But since you didn't mention any errors and $facebook->getUser(); executes I'm guessing this is just a bad copy-paste.
Now for the sake of answering this question I'm going to presume that you are using the latest versions of both JS and PHP SDKs. These use oauth 2.0 and change the way you pass the login information from JS to PHP.
According to Facebook Developer Blog removing $config['cookie'] = true; and setting oauth to true in your JS configuration should work. Just make sure to refresh the site after the login.
The solution I've found in my own project is to disable cookies altogether and simply pass the access token to my PHP script.
In your JS call your PHP script like this (make sure to call this after the JS login!):
$.ajax({
url : "http://xxxxxo/bn/notification.php",
type : 'POST',
data: {
notify: notify,
token: FB.getAuthResponse()['accessToken'] // add your access token
},
success : function (result) {
console.log(result);
},
error : function () {
alert("error sending notification");
}
});
And in your PHP script add this after creating the FB object.
$facebook->setAccessToken($_POST['token']); // set the users access token
Doing things this way will also get rid of any need to refresh the website after the login.
Yes, this is a common problem when using the PHP SDK in combination with AJAX:
When you make an AJAX request, the PHP SDK deletes the cookies where the authorization information are stored, and then the next call to getUser will just return 0, because this method tries to find the current user id in those cookies – apparently there is something in the OAuth 2.0 spec that demands this behavior to prevent some sort of click-jacking attack.
But the info will still be stored in the session, so you can read the user id (and the user access token, should you need it) from there:
$user_id = $_SESSION['fb_YourAppIdHere_user_id'];
$user_access_token = $_SESSION['fb_YourAppIdHere_access_token'];
Replace YourAppIdHere with your app id (so it becomes fb_1234567890_user_id resp. fb_1234567890_access_token) to get the correct names of those session keys.

Facebook API - App using Oauth to update status of page

I have built an app using the PHP Facebook SDK. It allows users to authenticate my app with facebook OAth so that they can update their status' via my App. This works great, however a lot of my users have business pages and they want to update the status on their business page not their main personal feed. How is this possible? Below is what I have so far.
if ($status != ''){
try {
$parameters = array(
'message' => "$status"/*,
'picture' => $_POST['picture'],
'link' => $_POST['link'],
'name' => $_POST['name'],
'caption' => $_POST['caption'],
'description' => $_POST['description']*/
);
//add the access token to it
$parameters['access_token'] = $access_token;
//build and call our Graph API request
$newpost = $facebook->api(
'/me/feed',
'POST',
$parameters
);
$success['status'] = "$xml->status";
$xml2 = new XMLGenerator($success, 'facebook','status');
$returnData = $xml2->output;
$returnData = APIResponse::successResponse('200', "$xml->status");
} catch (Exception $e) {
$returnData = APIResponse::errorResponse('400', 'Facebook Error: '.$e);
}
I assume I would have to change '/me/feed'? but to what? What is they have multiple pages how would my app know which page to post to?
Any help with this would be much appreciated.
You can substitute me with the PAGE_ID to post to a page e.g., /013857894/feed. Make sure that you have completed the OAuth process with the manage_pages and publish_stream permissions. You can learn more at the link below:
https://developers.facebook.com/docs/reference/api/page/#statuses
If the user has multiple Pages then you will first need to give them some way of selecting which page they want to post to. You can find out which Facebook Pages a given user is the administrator of by calling /me/accounts for that user. You can find out more about this approach in the Connections section of this page:
https://developers.facebook.com/docs/reference/api/user/

Facebook OAuthException: (#1)

I have a few applications which upload image to user profile. A few hours ago all applications were working fine but now when uploading is requested, it gives this error
Fatal error: Uncaught OAuthException: (#1) An unknown error occurred thrown in applications/fb-sdk/facebook.php on line 543
I'm using the following code to publish image.
$FILE = "images/$image";
$args = array('message' => 'My msg ');
$args['image'] = '#' . realpath($FILE);
$data = $facebook->api('/'.$uid.'/photos', 'post', $args);
Is it because of some policy change or some new feature?
I have all the permissions like upload is set to true and application takes permission to upload file.
P.s: when the application is used 2nd time, it works fine.
You need to verify if the user is logged in AND has the permissions to post on wall. We're going to do that with a TRY/CATCH with a call to the user.
$userId = $facebook -> getUser();
if ($userId) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
$userId = NULL;
error_log($e);
}
}
$app_permissions = array(
'scope' => 'publish_stream'
);
$logoutUrl = $facebook->getLogoutUrl();
$loginUrl = $facebook->getLoginUrl($app_permissions);
If the user is not logged in OR has authorized the app, you'll need to redirect him via header redirect or with a link.
if ($userId){
//Then you can call the facebook api
$data = $facebook->api('/'.$uid.'/photos', 'post', $args);
//... ...
}
That's the easiest way i've found.
EDIT : This question on stack has helped me : Facebook PHP SDK Upload Photos
No, the error is caused by the system cannot get the image file. Facebook will not allow the empty image field appear in the api. So it return Fatal error: Uncaught OAuthException: (#1) --- although it does not relate to the OAuth and OAuthException.