Verify id_token Using a Google API Client Library in PHP - php

I already have the id_token and it works fine for Calling the token info endpoint but the Google API Client Library for PHP return no result on verifyIdToken() I can't figure out why as no error is thrown any idea on how to fix this?
include_once('google-api-php-client-2.1.1/vendor/autoload.php');
$id_token = trim($_GET['id_token']);
$CLIENT_ID = 'XXXXXXXXXX-o36ncvcpbpo9uiiejb0qXXXXX8820tom.apps.googleusercontent.com';
$client = new Google_Client(['client_id' => $CLIENT_ID]);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
echo 'your id: ' . $userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
// Invalid ID token
echo 'invalid token';
}
At the end it still print invalid token

Related

Bing Ads api - invalid credentials error

So, our BingAds reporting program, which has been running for many months, is suddenly plagued with 105 (InvalidCredentials) errors. The access token had expired, so I requested a new one, which succeeds, giving me a new access token that expires in the future.
$accessTokenExchangeUrl = "https://login.live.com/oauth20_token.srf";
$accessTokenExchangeParams = array();
$accessTokenExchangeParams['client_id'] = $this->client_id();
$accessTokenExchangeParams['client_secret'] = $this->client_secret();
$accessTokenExchangeParams['grant_type'] = 'refresh_token';
$accessTokenExchangeParams['refresh_token'] = $code;
// Create an HTTP client and execute an HTTP POST request to
// exchange the authorization token for an access token and
// refresh token.
$httpClient = new HttpClient();
$responseJson = $httpClient->postData( $accessTokenExchangeUrl, $accessTokenExchangeParams);
// The response formatted in json
$responseArray = json_decode($responseJson, TRUE);
// If the response contains an access_token element, it was successful.
// If not, an error occurred - throw an exception
if (isset($responseArray['access_token']))
{
return $responseArray;
}
But then using that new token results in a 105 error:
$proxy = \BingAds\Proxy\ClientProxy::ConstructWithCredentials($wsdl, $bingUserName,
$bingPasswd,
$developer_token,
$access_token);
$report = new KeywordPerformanceReportRequest();
$report->Format = ReportFormat::Tsv;
$report->ReportName = 'Keyword Performance Report';
$report->ReturnOnlyCompleteData = false;
<report definition>
$encodedReport = new SoapVar($report, SOAP_ENC_OBJECT, 'KeywordPerformanceReportRequest', $proxy->GetNamespace());
$this->bingReportRequestID = $this->_BingSubmitGenerateReport( $proxy, $encodedReport );
$request = new SubmitGenerateReportRequest();
$request->ReportRequest = $report;
$retval = $proxy->GetService()->SubmitGenerateReport($request)->ReportRequestId;
::> throws a SoapFault
Any ideas? Like I said, it was working fine for months, now suddenly, nothing.
Apparently you are using a refresh_token to authenticate. With the new token you got, you need to generate you new refresh_token and use that one instead.

Google Client API - Missing require parameter: redirect_uri

So I followed the quickstart guide and decided to break it into a class called scheduler. I am working on the the authentication code, but I keep getting this: "Error 400 (OAuth 2 Error) Error Invalid Request Missing required Parameter: redirect_uri".
class scheduler{
//The Google Client object
private $googleClient;
//the Google Calendar Service ojbect
private $calendarService;
/*
* Google Calendar Setup
*
* This creates a Google Client object so that you may create a Google Calendar object.
*
*/
function __construct(){
//set the application name
define("APPLICATION_NAME", "Web client 1");
//
define("CREDENTIALS_PATH", "~/scheduler/credentials.json");
//
define("CLIENT_SECRET_PATH", __DIR__ . "/scheduler/client_secret.json");
//
define("SCOPES", implode(" ", array(Google_Service_Calendar::CALENDAR_READONLY)));
/*if(php_sapi_name() != "cli"){
throw new Exception("This application must be run on the command line");
}*/
//create the google client
$this->googleClient = new Google_Client();
//setup the client
$this->googleClient->setApplicationName(APPLICATION_NAME);
$this->googleClient->setDeveloperKey("AIzaSyBmJLvNdMYuFhVpWalkUdyStrEBoVEayYM");
$this->googleClient->setScopes(SCOPES);
$this->googleClient->setAuthConfigFile(CLIENT_SECRET_PATH);
$this->googleClient->setAccessType("offline");
//get the credentials file path
$credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
//if the file exists
if(file_exists($credentialsPath)){
//get the credentials from the file
$accessToken = file_get_contents($credentialsPath);
}//if it does not
else{
//request the authorization url
$authURL = $this->googleClient->createAuthUrl();
//print the authorization ulr
echo "Press Me<br /><br />";
//prompt the user to enter the auth code
print("Enter authentication code: ");
//
$authCode = trim(fgets(STDIN));
//exchange authorization for an access token
$accessToken = $this->googleClient->authenticate($authCode);
//store credentials to disk
if(!file_exists(dirname($credentialsPath))){
mkdir(dirname($credentialsPath), 0700, true);
}
//put the contents into the credential files
file_put_contents($credentialsPath, $accessToken);
}
$this->googleClient->setAccessToken($accessToken);
//refresh token if its expired
if($this->googleClient->isAccessTokenExpired()){
$this->googleClient->refreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, $this->googleClient->getAccessToken());
}
}
I found the cause of the problem with no solution in sight. Under my Google Developer Console I tried putting "http://localhost/" into the Authorized redirect URIs section. It gives me this error "Sorry, there’s a problem. If you entered information, check it and try again. Otherwise, the problem might clear up on its own, so check back later." Is there a way to make Google Developer Console to accept the redirect uri of a localhost server?
Just use method setRedirectUri($absoluteUrl) on a client object:
$client = new Google_Client();
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
via:
https://developers.google.com/api-client-library/php/auth/web-app
I got it to work. What I had to do was go back into Google Developer Console and delete the project I had created. Then when making a NEW project it allowed me to save my localhost url. The issue that was occuring was when I went to go add my localhost url to the redirect url it would say its not possible at this time. When I set the redirect url before hitting the create button it accepts it just fine.
Google's "PHP Quick Start" documentation for the Sheet API seems to be out of date at https://developers.google.com/sheets/api/quickstart/php.
To get their demo working with PHP 7.2+ I had to modify quite a bit, and it's not all that clear what's going on. Below is a commented, updated version of their quick start that may be helpful to anyone else having trouble working with the Google Sheets API and PHP.
<?php
/**
* Updated Google Sheets Quickstart
*
* https://developers.google.com/sheets/api/quickstart/php
*/
require __DIR__ . '/vendor/autoload.php';
/**
* Appends one slash at the end, and removes any extra slashes
* https://stackoverflow.com/a/9339669/812973
*
* #return string $path with the slash appended
*/
function addTrailingSlash ($path)
{
return rtrim ($path, '/') . '/';
}
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient() {
// Change this to a secure location where you'll save your config *.json files
// Make sure it isn't publicly available on the web
$configPath = addTrailingSlash (getcwd());
// This get's generated by the script, so don't create it
$credentialsPath = $configPath . 'credentials.json';
$client = new Google_Client();
// Matches the "Application Name" you enter during the "Step 1" wizard
$client->setApplicationName( 'API App Name' );
$client->setScopes( Google_Service_Sheets::SPREADSHEETS_READONLY );
// You need to go through "Step 1" steps to generate this file: https://developers.google.com/sheets/api/quickstart/php
$client->setAuthConfig( $configPath . 'client_secret.json' );
$client->setAccessType( 'offline' );
// This must match the "callback URL" that you enter under "OAuth 2.0 client ID" in the Google APIs console at https://console.developers.google.com/apis/credentials
$client->setRedirectUri( 'https://' . $_SERVER['HTTP_HOST'] . '/' . basename( __FILE__, '.php' ) );
// We have a stored credentials file, try using the data from there first
if ( file_exists( $credentialsPath ) ) {
$accessToken = json_decode( file_get_contents( $credentialsPath ), true );
}
// No stored credentials found, we'll need to request them with OAuth
else {
// Request authorization from the user
$authUrl = $client->createAuthUrl();
if ( ! isset( $_GET['code'] ) ) {
header( "Location: $authUrl", true, 302 );
exit;
}
// The authorization code is sent to the callback URL as a GET parameter.
// We use this "authorization code" to generate an "access token". The
// "access token" is what's effectively used as a private API key.
$authCode = $_GET['code'];
$accessToken = $client->fetchAccessTokenWithAuthCode( $authCode );
// Create credentials.json if it doesn't already exist (first run)
if ( ! file_exists( dirname( $credentialsPath ) ) ) {
mkdir( dirname( $credentialsPath ), 0700, true );
}
// Save the $accessToken object to the credentials.json file for re-use
file_put_contents( $credentialsPath, json_encode( $accessToken ) );
}
// Provide client with API access token
$client->setAccessToken( $accessToken );
// If the $accessToken is expired then we'll need to refresh it
if ( $client->isAccessTokenExpired() ) {
$client->fetchAccessTokenWithRefreshToken( $client->getRefreshToken() );
file_put_contents( $credentialsPath, json_encode( $client->getAccessToken() ) );
}
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets( $client );
// Get values from a spreadheet and print
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();
if (empty($values)) {
print "No data found.\n";
} else {
print "Name, Major:\n";
foreach ($values as $row) {
// Print columns A and E, which correspond to indices 0 and 4.
printf("%s, %s\n", $row[0], $row[4]);
}
}
This answer might not fully satisfy your needs, but:
If you only need read access to the sheet, all you need is a Google Service Account credentials file (credentials.json).
One can simply slice out the token-retrieving part of the example like so:
<?php
require __DIR__ . '/vendor/autoload.php';
if (php_sapi_name() != 'cli') {
throw new Exception('This application must be run on the command line.');
}
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Google Sheets API PHP Quickstart');
$client->setScopes(Google_Service_Sheets::SPREADSHEETS_READONLY);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets($client);
// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();
if (empty($values)) {
print "No data found.\n";
} else {
print "Name, Major:\n";
foreach ($values as $row) {
// Print columns A and E, which correspond to indices 0 and 4.
printf("%s, %s\n", $row[0], $row[4]);
}
}
Google should have mentioned this in their example IMO.
My problem was i'm not initialized the URI in Google Console
to fix the problem :
1- go to your project https://console.cloud.google.com/ (Select project from top)
2- Search for "Google sheet API" make sure it's enabled
3- On left menu Click on "Credentials"
4- If you're already created "OAuth 2.0 Client IDs" just click on edit and add URI else create new "OAuth 2.0 Client IDs"
5- Remember to re-download "OAuth 2.0 Client IDs" it will be something like "client_secret_XXX.apps.googleusercontent.com" rename it to credentials.json and set it on your project
Just improving the answer of #kevinLeary so the code can looks more modular:
<?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';
$redirect_url = 'http://' . $_SERVER['HTTP_HOST'] . '/mydrive/index.php'; // <--- Change it to your web application path, host will be detected automatically
$auth_file = __DIR__ . DIRECTORY_SEPARATOR . 'drive-auth.json'; // <--- Your auth2 settings
$auth_file = str_replace('\\', '/', $auth_file);
$configPath = addTrailingSlash(getcwd());
$credentials_file = $configPath . 'credentials.json'; // <--- This will generated automatically
$app_name = 'MY APP NAME';
$scopes = [
Google_Service_Sheets::SPREADSHEETS_READONLY,
];
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient($app_name, $auth_file, $credentials_file, $redirect_url, $scopes = array()) {
// This get's generated by the script, so don't create it
$credentialsPath = $credentials_file;
$client = new Google_Client();
// Matches the "Application Name" you enter during the "Step 1" wizard
$client->setApplicationName( $app_name );
$client->setScopes( $scopes );
// You need to go through "Step 1" steps to generate this file: https://developers.google.com/sheets/api/quickstart/php
$client->setAuthConfig( $auth_file );
$client->setAccessType( 'offline' );
// This must match the "callback URL" that you enter under "OAuth 2.0 client ID" in the Google APIs console at https://console.developers.google.com/apis/credentials
$client->setRedirectUri( $redirect_url );
// We have a stored credentials file, try using the data from there first
if ( file_exists( $credentialsPath ) ) {
$accessToken = json_decode( file_get_contents( $credentialsPath ), true );
}
// No stored credentials found, we'll need to request them with OAuth
else {
// Request authorization from the user
$authUrl = $client->createAuthUrl();
if ( ! isset( $_GET['code'] ) ) {
header( "Location: $authUrl", true, 302 );
exit;
}
// The authorization code is sent to the callback URL as a GET parameter.
// We use this "authorization code" to generate an "access token". The
// "access token" is what's effectively used as a private API key.
$authCode = $_GET['code'];
$accessToken = $client->fetchAccessTokenWithAuthCode( $authCode );
// Create credentials.json if it doesn't already exist (first run)
if ( ! file_exists( dirname( $credentialsPath ) ) ) {
mkdir( dirname( $credentialsPath ), 0700, true );
}
// Save the $accessToken object to the credentials.json file for re-use
file_put_contents( $credentialsPath, json_encode( $accessToken ) );
}
// Provide client with API access token
$client->setAccessToken( $accessToken );
// If the $accessToken is expired then we'll need to refresh it
if ( $client->isAccessTokenExpired() ) {
$client->fetchAccessTokenWithRefreshToken( $client->getRefreshToken() );
file_put_contents( $credentialsPath, json_encode( $client->getAccessToken() ) );
}
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets( $client );
// Get values from a spreadheet and print
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();
if (empty($values)) {
print "No data found.\n";
} else {
print "Name, Major:\n";
foreach ($values as $row) {
// Print columns A and E, which correspond to indices 0 and 4.
printf("%s, %s\n", $row[0], $row[4]);
}
}
function addTrailingSlash ($path)
{
return rtrim ($path, '/') . '/';
}
?>

Invlid_grant When trying to refresh token - Google Oauth - PHP

just started using google admin SDK,trying to retrieve specific user's infomation.
i keep getting the same error over and over
[29-May-2015 14:41:18 Africa/Tunis] PHP Fatal error: Uncaught
exception 'Google_Auth_Exception' with message 'Error refreshing the
OAuth2 token, message: '{ "error" : "invalid_grant"
during my research i found that it's mostly a syncing problem(server time)
but my web app is hosted on a third party server.checked my service account credentials
Ps: don't know if it matters but the server's time zone is GMT+1
`
<?php
require 'src/Google/autoload.php';
session_start();
$timestamp = $_SERVER['REQUEST_TIME'];
echo gmdate("Y-m-d\TH:i:s\Z", $timestamp);
$service_account_name = "xx";
$key_file_location = "yyy.p12";
$client = new Google_Client();
$client->setApplicationName("Members");
$directory = new Google_Service_Directory($client);
if (isset($_SESSION['service_token']) && $_SESSION['service_token']) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
// Replace this with the email address from the client.
$service_account_name,
// Replace this with the scopes you are requesting.
array('https://www.googleapis.com/admin/directory/v1/users'),
$key,
'notasecret'
);
$cred->sub = "admin-email";
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
$email = "personto lookfor-email";
$r = $dir->users->get($email);
if($r) {
echo "Name: ".$r->name->fullName."<br/>";
echo "Suspended?: ".(($r->suspended === true) ? 'Yes' : 'No')."<br/>";
echo "Org/Unit/Path: ".$r->orgUnitPath."<br/>";
} else {
echo "User does not exist: $email<br/>";
// if the user doesn't exist, it's safe to create the new user
}
`
The reason of the "Invalid grant" error may be due to the refresh token not working. This happens When the number of refresh tokens exceeds the limit, older tokens become invalid. If the application attempts to use an invalidated refresh token, an invalid_grant error response is returned. Here is the link for more documentation.

Laravel webapp login from iOS with Facebook SDK

i have a webapp working with Laravel.
i have some users registered in my webapp.
users who dont want to create a account can use Facebook/Google+ login.
to make Facebook/Google+ connection, i used a oAuth2 connexion with :
oauth-4-laravel
on the iOS application, users can login using username and password but they can login too with Facebook/Google+ using FB/G+ SDK.
my questions is, how to login on my webapp users from iOS who are connected by Facebook/Google+.
artdarek/oauth-4-laravel require a "code" given by the social network, and i dont know how to get it on iOS.
here the code for users who want to connect to the webapp by web browser :
public function loginWithFacebook() {
// get data from input
$code = Input::get( 'code' );
// get fb service
$fb = OAuth::consumer( 'Facebook' );
// check if code is valid
// if code is provided get user data and sign in
if ( !empty( $code ) ) {
// This was a callback request from facebook, get the token
$token = $fb->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $fb->request( '/me' ), true );
// $message = 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
//echo $message. "<br/>";
//Var_dump
//display whole array().
// dd($result);
if (User::where('fb_id','=', $result['id'])->count() == 0) {
$user = new User;
$user->firstname = $result['first_name'];
$user->lastname = $result['last_name'];
$user->username = $result['email'];
$user->email = $result['email'];
$user->fb_id = $result['id'];
$user->yearofbirth = substr($result['birthday'],6,9);
$user->fk_role=3;
if ($result['gender'] == 'male') {
$user->sex = 1;
}
else{
$user->sex = 0;
}
$user->save();
}
else{
$user = User::where('fb_id','=', $result['id'])->first();
}
Auth::login($user);
Userslog::log('desktop_facebook_login');
return Redirect::to('/')->with('message', 'Logged in with Facebook');
}
// if not ask for permission first
else {
// get fb authorization
$url = $fb->getAuthorizationUri();
// return to facebook login url
return Redirect::to( (string)$url );
}
}
i finally find a solution in the issues of oauth-4-laravel on github,
i just have to use iOS AccessToken and connect the user to the webapp using this token.
here the code laravel code to use the Token ;)
use OAuth\OAuth2\Token\StdOAuth2Token;
$token_interface = new StdOAuth2Token(Input::get( 'token' ));
$network = OAuth::consumer( 'Facebook' );
$network->getStorage()->storeAccessToken('Facebook', $token_interface);
$result = json_decode( $network->request( '/me' ), true );
$fb_id = $result['id'];
To Resume,
the best way is ; to login with Facebook/Google+ on iOS,
when login finish with success, get the AccessToken and send to the webapp.And then the webapp use you token to login again the user to Facebook/Google+ and finally , the user is verified and you can login it to laravel webapp.
have a nice day.
I'm quite in the same situation here.
With the solution you provide, how are you preventing other applications to send their own AccessToken and access your Laravel application?
I assume you send the token via a POST request from you iOS app to a certain endpoint of your Laravel app, therefore any developper knowing this endpoint could pretend to be logged on your mobile application, no?

got a 401 when I get access token for LinkedIn

$oauth->getAccessToken() causes Invalid auth/bad request (got a 401, expected HTTP/1.1 20X or a redirect).
How do I look at the request headers to figure out what exactly is wrong?
$oauth = new OAuth(CONSUMER_KEY, CONSUMER_SECRET);
$oauth->disableSSLChecks();
$request_token_response = $oauth->getRequestToken('https://api.linkedin.com/uas/oauth/requestToken');
if($request_token_response === FALSE) {
throw new Exception("Failed fetching request token, response was: " . $oauth->getLastResponse());
} else {
$request_token = $request_token_response;
var_dump($request_token);
if (!isset($_GET['oauth_verifier'])) {
$this->redirect("https://api.linkedin.com/uas/oauth/authorize?oauth_token=" . $request_token['oauth_token']);
} else {
$oauth_verifier = $_GET['oauth_verifier'];
$oauth->setToken($request_token['oauth_token'], $request_token['oauth_token_secret']);
$access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken';
$access_token_response = $oauth->getAccessToken($access_token_url, "", $oauth_verifier);
if($access_token_response === FALSE) {
throw new Exception("Failed fetching request token, response was: " . $oauth->getLastResponse());
} else {
$access_token = $access_token_response;
$params = array();
$headers = array();
$method = OAUTH_HTTP_METHOD_GET;
// Specify LinkedIn API endpoint to retrieve your own profile
$url = "http://api.linkedin.com/v1/people/~";
// By default, the LinkedIn API responses are in XML format. If you prefer JSON, simply specify the format in your call
// $url = "http://api.linkedin.com/v1/people/~?format=json";
// Make call to LinkedIn to retrieve your own profile
$oauth->fetch($url, $params, $method, $headers);
echo $oauth->getLastResponse();
}
}
}
}
oauth_verifier only verifies the request_token from which it was obtained. I needed to store the original request_token in session instead of getting a new request_token on callback.

Categories