I'm facing problems fetching data (Profile list to be specific) from google analytics. The credentials like client_id, secret etc are in place and it does allow user to login successfully, but I'm stuck in the next step where I need to fetch the list of profiles (list of websites). I did go through the official docs as per Google Views (Profiles): list but while I try it, I get an error:
Undefined property: App\Http\Controllers\UserController::$analytics
the detailed error:
in UserController.php line 84
at HandleExceptions->handleError('8', 'Undefined property: App\Http\Controllers\UserController::$analytics', 'C:\xampp\htdocs\Laravel Projects\testApp\app\Http\Controllers\UserController.php', '84', array('request' => object(Request), 'google_redirect_url' => 'http://localhost:8000/glogin', 'gClient' => object(Google_Client), 'google_oauthV2' => object(Google_Service_Oauth2), 'guser' => null, 'user' => object(User), 'token' => array('access_token' => 'TOKEN GOES HERE', 'token_type' => 'Bearer', 'expires_in' => '3600', 'id_token' => 'ID_TOKEN GOES HERE', 'created' => 'CREATED DATA GOES HERE'))) in UserController.php line 84
I do understand there's an error when I try to fetch the data, but then I don't really understand as to how should i be doing that. Anyone has any idea? Please help!
here's the Controller
class UserController extends Controller
{
public function googleLogin(Request $request) {
$google_redirect_url = route('glogin');
$gClient = new \Google_Client();
$gClient->setApplicationName(config('services.google.app_name'));
$gClient->setClientId(config('services.google.client_id'));
$gClient->setClientSecret(config('services.google.client_secret'));
$gClient->setRedirectUri($google_redirect_url);
$gClient->setDeveloperKey(config('services.google.api_key'));
$gClient->addScope(\Google_Service_Analytics::ANALYTICS_READONLY);
$gClient->addScope("email");
$gClient->addScope("profile");
$gClient->setAccessType("offline");
$google_oauthV2 = new \Google_Service_Oauth2($gClient);
if ($request->get('code')){
$gClient->authenticate($request->get('code'));
$request->session()->put('token', $gClient->getAccessToken());
}
if ($request->session()->get('token'))
{
$gClient->setAccessToken($request->session()->get('token'));
}
if ($gClient->getAccessToken())
{
//For logged in user, get details from google using access token
$guser = $google_oauthV2->userinfo->get();
$request->session()->put('name', $guser['name']);
if ($user =User::where('email',$guser['email'])->first())
{
}else{
//register your user with response data
return User::create([
'name' => $guser->name,
'email' => $guser->email,
]);
}
//LINE NO 84 is below:
$profiles = $this->analytics->management_profiles
->listManagementProfiles();
$accounts = $accountsObject->getItems();
return $accounts;
//return redirect()->route('user.glist');
} else
{
//For Guest user, get google login url
}
}
}
You are calling $this->analytics but nowhere do you define the property analytics for the UserController class. Not sure what is defined in the parent class Controller but I am pretty sure it is agnostic of the Analytics service object.
You need to instantiate the Google_Service_Analytics object.
// Create an authorized analytics service object.
$analytics = new Google_Service_Analytics($gclient);
See the Hello Analytics guide for details.
Related
I have Google Sheets API set up and working (I can read and update existing spreadsheets if it's shared to my credentials) and I need to export some data from my website to google sheet. In order to keep users off seeing other people's sheets, I need to create a new spreadsheet when user wants to export data. I managed to create new spreadsheet like this:
public function init(){
$user = Socialite::driver('google')->stateless()->user();
$token = [
'access_token' => $user->token,
'refresh_token' => $user->refreshToken,
'expires_in' => $user->expiresIn
];
$client = new \Google_Client();
$client->setApplicationName('Sheets');
$client->setScopes([\Google_Service_Sheets::SPREADSHEETS]);
$client->setAccessType('offline');
$client->setAuthConfig('../credentials.json');
$client->setAccessToken($token);
$service = new Google_Service_Sheets($client);
$serviceDrive = new Google_Service_Drive($client);
$spreadsheet = new Google_Service_Sheets_Spreadsheet([
'properties' => [
'title' => 'Testing Sheet'
]
]);
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId'
]);
$this->insertPermission($serviceDrive, $spreadsheet->spreadsheetId, $user->email, 'user', 'owner');
}
When I dd($spreadsheet) I can see that it's actually created and I can retrieve its id. But the thing is, if I try to open it, I get a notification that I need to get access as I don't have it. I searched for a solution a lot and tried several ways. I tried to pass a role like this:
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId',
'role' => 'owner'
'email' => 'useremail#gmail.com'
]);
Also tried to insert permission using this method:
function insertPermission($service, $fileId, $value, $type, $role) {
$newPermission = new Google_Service_Drive_Permission();
$newPermission->setEmailAddress($value);
$newPermission->setType($type);
$newPermission->setRole($role);
try {
return $service->permissions->create($fileId, $newPermission);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
But this method gives me an error when calling create() function which says "code": 403, "message": "Insufficient Permission: Request had insufficient authentication scopes.". Is there a way to give to authenticated user an access to newly created spreadsheet and where is my mistake?
You are trying to give permission with the Drive API
Your code only contains $client->setScopes([\Google_Service_Sheets::SPREADSHEETS]);
To use both the Sheets and the Drive API with the same client, assign to the client BOTH respective scopes
I would like to access the global address book of an organization through outlook rest api
I was able to implement the Single Sign-on part using OAUTH2 but I'm unable to understand how to access the contacts object
I have gone through this
and many other examples but unable to understand how to implement them in PHP
Firstly, if you want to use the rest api to access the outlook contacts, at the moment, Microsoft suggests customers use the Microsoft Graph. For more details, please refer to the document
Secondly, regarding how to get outlook conatcts with php application, you need to use oauth2-client to add Azure AD authentication and get Azure AD access token then call the api to get contacts with the access token. For example, please refer to the following steps to know how to implement it in php web application
Register Azure AD application
Configure app permissions you need for your application
Implement Azure AD authentication with the SDK oauth2-client
a. Create a .env file
OAUTH_APP_ID=YOUR_APP_ID_HERE
OAUTH_APP_PASSWORD=YOUR_APP_PASSWORD_HERE
OAUTH_REDIRECT_URI=<your redirect url>
OAUTH_SCOPES='openid profile offline_access' + <your need outlook permissions>
OAUTH_AUTHORITY=https://login.microsoftonline.com/common
OAUTH_AUTHORIZE_ENDPOINT=/oauth2/v2.0/authorize
OAUTH_TOKEN_ENDPOINT=/oauth2/v2.0/token
b. Get access token
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AuthController extends Controller
{
public function signin()
{
// Initialize the OAuth client
$oauthClient = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => env('OAUTH_REDIRECT_URI'),
'urlAuthorize' => env('OAUTH_AUTHORITY').env('OAUTH_AUTHORIZE_ENDPOINT'),
'urlAccessToken' => env('OAUTH_AUTHORITY').env('OAUTH_TOKEN_ENDPOINT'),
'urlResourceOwnerDetails' => '',
'scopes' => env('OAUTH_SCOPES')
]);
$authUrl = $oauthClient->getAuthorizationUrl();
// Save client state so we can validate in callback
session(['oauthState' => $oauthClient->getState()]);
// Redirect to AAD signin page
return redirect()->away($authUrl);
}
public function callback(Request $request)
{
// Validate state
$expectedState = session('oauthState');
$request->session()->forget('oauthState');
$providedState = $request->query('state');
if (!isset($expectedState)) {
// If there is no expected state in the session,
// do nothing and redirect to the home page.
return redirect('/');
}
if (!isset($providedState) || $expectedState != $providedState) {
return redirect('/')
->with('error', 'Invalid auth state')
->with('errorDetail', 'The provided auth state did not match the expected value');
}
// Authorization code should be in the "code" query param
$authCode = $request->query('code');
if (isset($authCode)) {
// Initialize the OAuth client
$oauthClient = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => env('OAUTH_REDIRECT_URI'),
'urlAuthorize' => env('OAUTH_AUTHORITY').env('OAUTH_AUTHORIZE_ENDPOINT'),
'urlAccessToken' => env('OAUTH_AUTHORITY').env('OAUTH_TOKEN_ENDPOINT'),
'urlResourceOwnerDetails' => '',
'scopes' => env('OAUTH_SCOPES')
]);
try {
// Make the token request
$accessToken = $oauthClient->getAccessToken('authorization_code', [
'code' => $authCode
]);
return redirect()->route('contacts');
}
catch (League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
return redirect('/')
->with('error', 'Error requesting access token')
->with('errorDetail', $e->getMessage());
}
}
return redirect('/')
->with('error', $request->query('error'))
->with('errorDetail', $request->query('error_description'));
}
}
```
Use the access token With Microsoft Graph SDK. For more details, please refer to the docuemnt
public function mail()
{
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$tokenCache = new \App\TokenStore\TokenCache;
$graph = new Graph();
$graph->setAccessToken($tokenCache->getAccessToken());
$contacts = $graph->createRequest('GET', '/me/contacts/{Id}')
->setReturnType(Model\Contact::class)
->execute();
}
Regarding the details of how to implement it, please refer to the sample
Besides, if you want to call the outlook rest api with php, please refer to the document. But please note that you need to change the app permissions.
I am trying to add social authentication to a Laravel 5.8 API project using socialite.
When trying to handle a social provide callback, the ArgumentCountError is thrown here
Too few arguments to function App\Http\Controllers\SocialAuthController::handleProviderCallback(), 0 passed and exactly 1 expected
The error is referring to the very first line of this code block
public function handleProviderCallback($provider)
{
// retrieve social user info
$socialUser = Socialite::driver($provider)->stateless()->user();
// check if social user provider record is stored
$userSocialAccount = SocialAccount::where('provider_id', $socialUser->id)->where('provider_name', $provider)->first();
if ($userSocialAccount) {
// retrieve the user from users store
$user = User::find($userSocialAccount->user_id);
// assign access token to user
$token = $user->createToken('Pramopro')->accessToken;
// return access token & user data
return response()->json([
'token' => $token,
'user' => (new UserResource($user))
]);
} else {
// store the new user record
$user = User::create([
'name' => $socialUser->name,
'username' => $socialUser->email,
'email_verified_at' => now()
]);
...
// assign passport token to user
$token = $user->createToken('******')->accessToken;
// return response
return response()->json(['token' => $token]);
}
}
Below is how I have set up other code. Frist in env I added
GOOGLE_CLIENT_ID=******
GOOGLE_CLIENT_SECRET=*******
GOOGLE_CALLBACK_URL=https://staging.appdomain.com/api/v1/user
Then modified web.php
Auth::routes(['verify' => true]);
Route::get('/auth/{provider}', 'SocialAuthController#redirectToProvider');
Route::get('/auth/{provider}/callback', 'SocialAuthController#handleProviderCallback');
Lastly in the google app, I added the uri path where users will be redirected to after successful authentication
https://staging.appdomain.com/api/v1/user
How do I fix this?
The callback uri that user should be redirected to after successful authentication was apparently not being cached. So running php artisan route:cache fixed it.
Till 3 days ago, our login service was working fine. Now its broken by a unknown problem with Facebook oAuth.
Our app (built with React Native using native FBSDK), ask for Facebook for an Access Token and forward it to our API.
LoginManager.logInWithReadPermissions(['public_profile', 'email'])
Then, our API try to validate the token against Facebook Graph API. Basically we do this:
public static function getInformationFromFacebook($accessToken)
{
$facebook = new Facebook([
'app_id' => config('services.facebook.app_id'),
'app_secret' => config('services.facebook.app_secret'),
'default_graph_version' => config('services.facebook.default_graph_version'),
]);
try {
$response = $facebook
->get('/me?fields=first_name,last_name,email,picture.type(large)', $accessToken);
} catch (FacebookResponseException $e) {
Log::error(sprintf('Graph returned an error: %s', $e->getMessage()));
throw new \Exception("Facebook graph error.");
} catch (FacebookSDKException $e) {
Log::error(sprintf('Facebook SDK returned an error: %s', $e->getMessage()));
throw new \Exception("Facebook SDK error.");
}
$graph = $response->getGraphUser();
return [
'first_name' => $graph->getFirstName(),
'last_name' => $graph->getLastName(),
'email_address' => $graph->getEmail(),
'picture' => $graph->getPicture()->getUrl(),
];
}
This piece of code uses Laravel 5.2 running with PHP 7.2 with the native Facebook SDK.
The expected behavior is an array with the user data, but it only works at local environment, when we try to debug this on staging server, the scopes from the user's access token are lost.
We discovered that we scopes are lost using this Facebook debug tool
// The OAuth 2.0 client handler helps us manage access tokens
$oAuth2Client = $facebook->getOAuth2Client();
// Get the access token metadata from /debug_token
$tokenMetadata = $oAuth2Client->debugToken($accessToken);
echo '<h3>Metadata</h3>';
var_dump($tokenMetadata);die;
Basically, when we're at the local the scopes are
'scopes' =>
array (size=2)
0 => string 'email' (length=5)
1 => string 'public_profile' (length=14)
when we change the call to the staging environment, the result is
["scopes"]=>
array(0) {
}
We tried all kind of things, even updating our SDK.
I'm currently trying to implement a way to synchronize my PHP App calendar with the Outlook calendar of my clients, using Azure API.
I use OAuth2 and the custom Microsoft provider by Steven Maguire.
I currently run in an issue where I get an error in my response :
{"error":"unsupported_grant_type","error_description":"The provided value for the input parameter 'grant_type' is not valid. Expected values are the following: 'authorization_code', 'refresh_token'."}
I'm having trouble understanding why the grant_type password is not supported, even though it says on the documentation of Azure that it is.
The request looks like this :
client_id=44bef79b-**********************&client_secret=H****************&redirect_uri=https%3A%2F%2F192.168.1.123%2Fmapeyral%2Fcalendarsync.php&grant_type=password&username=******************&password=***********&scope=openid%20profile%20offline_access%20Calendars.ReadWrite
The Authorize url used is : https://login.live.com/oauth20_token.srf
as defined in the Steven Maguire provider.
The header contains the content-type application/x-www-form-urlencoded (I've seen a lot of post where this was what caused the error).
Some of my code :
$this->provider = new Microsoft([
'clientId' => MicrosoftGraphConstants::CLIENT_ID,
'clientSecret' => MicrosoftGraphConstants::CLIENT_SECRET,
'redirectUri' => MicrosoftGraphConstants::REDIRECT_URI,
'urlAuthorize' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::AUTHORIZE_ENDPOINT,
'urlAccessToken' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => MicrosoftGraphConstants::RESOURCE_ID,
'scope' => MicrosoftGraphConstants::SCOPES
]);
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_GET['code']))
{
// Try getting access token from Database
$workingAccount = $GLOBALS['AppUI']->getState('working_account');
if (isset($workingAccount))
{
// DB access
$DB = new DatabaseConnection();
$dbAccess = $DB->getConnection();
$contactData = DBUserUtils::getContactDataFromEmail($GLOBALS['AppUI']->getState('working_account'), $dbAccess);
// If at least one user contact found
if (!is_null($contactData))
{
// If has refresh token => fill session variables using refresh token
if (!is_null($contactData['contact_refreshToken']))
{
log_msg('debug.log', 'Has refresh token');
$GLOBALS['AppUI']->setState('preferred_username', $contactData['contact_email']);
$GLOBALS['AppUI']->setState('given_name', $contactData['contact_first_name']." ".$contactData['contact_last_name']);
// Get new tokens
$newAccessToken = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $contactData['contact_refreshToken']
]);
// Update tokens and DB
$GLOBALS['AppUI']->setState('refresh_token', $newAccessToken->getRefreshToken());
$GLOBALS['AppUI']->setState('access_token', $newAccessToken->getToken());
DBOAuthUtils::updateTokenForUser($contactData['contact_id'], $GLOBALS['AppUI']->getState('refresh_token'), $dbAccess);
$this->redirectTo($redirectURL);
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
function getAccessToken(){
$accessToken = $this->provider->getAccessToken('password', [
'username' => '*************',
'password' => '********',
'scope' => MicrosoftGraphConstants::SCOPES
]);
}
During the first try it doesn't pass the if (isset($workingAccount)) condition (as expected) and go straight to the last else.
Code is a bit ugly for now but I don't think it has an impact on my problem.
Any help would be appreciated !
Thanks
Edit : added code
That helped me, the problem was that I need to use Azure Active Directory and not Azure AD 2.0.
Problem solved !