I'm working on a web app that will require somewhat frequent access to Google Data APIs, so I decided to go with the "OAuth with Federated Login (Hybrid Protocol)" method for users to log into the app. I got the http://googlecodesamples.com/hybrid/ working (after some tweaks for PHP 5.3 compatibility), and am able to get an Access Token. What's the next step? How do I use this access token?
It seems like I'll need to create a local session for the user to browse the rest of the app. Will this need to be completely independent of the Google login, or how would you handle that?
Relevant: this application also needs a REST API, for which I was planning to use OAuth. Any recommendation on how to tie this in with authentication for the actual app?
I am using the PHP LightOpenID library (see on gitorious) for that. It handles all the authentication flow for us. You don't need to bother about token and stuff.
Here the page where I display the "Login with Google" link :
<?php
require_once 'openid.php';
$openid = new LightOpenID;
$openid->identity = 'https://www.google.com/accounts/o8/id';
$openid->required = array('contact/email');
$openid->returnUrl = 'http://my-website.com/landing-login.php'
?>
Login with Google
When the click on the link, a Google page will appear ask him to authenticate and/or authorize you to retrieve his email.
Then he will be redirect to the landing page $openid->returnUrl. The code for that page should be :
<?php
require_once 'openid.php';
$openid = new LightOpenID;
if ($openid->mode) {
if ($openid->mode == 'cancel') {
// User has canceled authentication
} elseif($openid->validate()) {
// Yeah !
$data = $openid->getAttributes();
$email = $data['contact/email'];
} else {
// The user has not logged in via Google
}
} else {
// The user does not come from the link of the first page
}
?>
If you want to retrieve more info from the user, you have to add them to $openid->required in the first page. For instance :
$openid->required = array(
'contact/email',
'namePerson/first',
'namePerson/last'
);
will let you, if the user accepts it, to get his first and last names as well in the second page :
$name = $data['namePerson/first'] . " " . $data['namePerson/last'];
Then, for the Oauth part, you can follow the instructions of this LightOpenID issue.
Related
I have a login script created which allows you to login through the Google API. Everything works fine and the redirect back to my website does also work.
Here is my script for the oauth callback:
<?php
require_once 'google-api-php-client-2.2.1/vendor/autoload.php';
session_start();
if (isset ($_GET["error"])) {
header('Location: #');
}
if (isset ($_GET["code"])) {
$client = new Google_Client();
$client->authenticate($_GET['code']);
$_SESSION['g_access_token'] = $client->getAccessToken();
$redirect = "http://".$_SERVER["HTTP_HOST"].$_SERVER["PHP_SELF"];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
if (isset ($_SESSION["g_access_token"])) {
$plus = new Google_Service_Plus($client);
$client->setAccesToken($_SESSION["g_access_token"]);
$me = $plus->people->get('me');
$_SESSION["unid"] = $me["id"];
$_SESSION["g_name"] = $me["displayName"];
$_SESSION["email"] = $me["emails"][0]["value"];
$_SESSION["g_profile_image_url"] = $me["image"]["url"];
$_SESSION["g_cover_image_url"] = $me["cover"]["coverPhoto"]["url"];
$_SESSION["g_profile_url"] = $me["url"];
}
?>
I dont get any error, but the session variables are still undefined. Where is the problem?
I just read and watched lots of tutorials, but still dont get it. Maybe somebody can help me here!
Thank you :)
EDIT
I just debugged my code and now I know that the Session Variable 'g_access_token' is empty after the login. So the main reason why it doesnt work should be the authentication. But I still dont know how to solve that...
I've just come from dealing successfully with Google OAuth API for PHP. So far, your code doesn't seem broke. Anyhow, it'd be nice to check your config file from which you get the class new Google_Client().
As that file is not posted in your question, i recommend you to follow this one, and call it through require_once to whenever you need it:
<?php
session_start();
require_once "GoogleAPI/vendor/autoload.php";
$gClient = new Google_Client();
$gClient->setClientId("your_client_id_comes_here");
$gClient->setClientSecret("your_client_secret");
$gClient->setApplicationName("CPI Login Tutorial");
$gClient->setRedirectUri("your_authorized_uri.php");
//addScope sets the permissions you'll have in your app, whether it is only for displaying them or to handle as you desire (e.g.: store account's information, such as email givenName and so on, into your own db
$gClient->addScope("https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.me");
?>
Also, don't you forget to enable the Google + API in your Google console. Finally, check that in your credentials, the "Authorized redirect URIs" contains the redirect uri you want the google api to callback once the user is authenticated.
I programmed a Google Login for my website. The user needs to use his or her specific school gmail. However, I run into a problem. If the user accidentally tries to login with another gmail that isn't his school email, the website warns him "You should be using your school gmail" and brings him back to the login page. However, if he tries to click "Login with Google" again (because ideally he would pick the correct Google email address), the session for his previous Google account is still running and doesn't even give him an option to try his other gmail account. I don't know exactly what to do...do I destroy the session? Does the user have to manually log out? Here is the error handling code.
unset($_SESSION['token']);
$authUrl = $client->createAuthUrl();
echo ("<SCRIPT LANGUAGE='JavaScript'>
window.alert('You need to login with your school Google account.')
window.location.href='http://websitename.com/login';
</SCRIPT>");
If after destroying your session google authentication URL redirects you directly to your redirect file, it is probably because no new google access token has to be assigned. In case you don't need to store and re-use the same access token and want the user to log in every time authenticating with Google, you have to revoke the token after using it.
In order to revoke an access token, you have to execute the following line
$client->revokeToken();
Example code for this behavior would be:
$client->setAccessToken($access_token);
if (!$client->isAccessTokenExpired()) {
try {
$plus = new Google_Service_Plus($client); // starts google profile (plus) service
$me = $plus->people->get('me'); // saves account info
$email = $me->emails[0]->value; // email
$id = $me->id; // id
$name = $me->name->givenName; // name
$surname = $me->name->familyName; // surname
$client->revokeToken();
$user = updateUser($email, $name, $surname, $id, $pic, $shortener); // proprietary function
} catch (Google_Exception $e) {
abortLogin("couldn't check google profile details", true); // proprietary function
}
} else {
abortLogin("invalid token", true); // proprietary function
}
session_destroy();
So I have recently integrated the new Office365 Rest API with PHP and have it working successfully with the Contacts API.
The system will generate the request url and redirect the user back once authentication is complete which works perfectly fine however if you go back to the script it will automatically log you through the process again as Office365 does not force reauthorisation.
Our script currently allows multiple users to sync their accounts with our system however this is only letting one user perform this per browser session.
require_once('./src/Office365_Client.php');
$client = new Office365_Client();
$forward_url = $client->createAuthUrl();
if (isset($_GET['code'])) {
$code = $_GET['code'];
$client->setCode($code);
$responseObj = $client->getTokens();
$access_token = $client->getAccessToken();
$refresh_token = $client->getRefreshToken();
$_SESSION['access_token'] = $access_token;
$_SESSION['instance_url'] = $instance_url;
$icustomer = (isset($_SESSION['icustomer'])) ? $_SESSION['icustomer'] : false;
header("location: " . $_SESSION['redirUrl'] . "?crm=office365&access_token=$access_token&refresh_token=$refresh_token");
//die();
//////////////////////////////////////////////////////////
// LOAD CONTACTS
/////////////////////////////////////////////////////////
//$client->getContactsFolders();
///////////////////////////////////////////////////
} else {
header("location: $forward_url");
}
Ideally it should work as followed:
User visits our website -> We generate Auth URL and the user is redirected to the Login Page for Office365 (They will then to autheticate if previously not done so) -> Once complete this will return them back to our selection screen with their code ready for their access token to be created. If the user wishes to add a different Office365 account they should be able to go through that process again without using a different browser.
Add prompt=login to the authorization request, so:
header("location: $forward_url" . "&prompt=login");
Have you tried logging out? The logout URI is https://login.windows.net/common/oauth2/logout. So you would want to do something like
https://login.windows.net/common/oauth2/logout?post_logout_redirect_uri=<some page in your app>
Looking at Dwolla's API documentation and trying the oauth.php example code (code shown below) on my site it is not clear to me if I can generate an access token without redirecting to Dwolla's page.
Redirecting from my site to their site back to my site is really terrible from a UI/UX perspective and is no better than the crappy interface Paypal provides.
Does anyone know how to generate a Dwolla access token using AJAX?
<?php
// Include the Dwolla REST Client
require '../lib/dwolla.php';
// Include any required keys
require '_keys.php';
// OAuth parameters
$redirectUri = 'http://localhost:8888/oauth.php'; // Point back to this file/URL
$permissions = array("Send", "Transactions", "Balance", "Request", "Contacts", "AccountInfoFull", "Funding");
// Instantiate a new Dwolla REST Client
$Dwolla = new DwollaRestClient($apiKey, $apiSecret, $redirectUri, $permissions);
/**
* STEP 1:
* Create an authentication URL
* that the user will be redirected to
**/
if(!isset($_GET['code']) && !isset($_GET['error'])) {
$authUrl = $Dwolla->getAuthUrl();
header("Location: {$authUrl}");
}
/**
* STEP 2:
* Exchange the temporary code given
* to us in the querystring, for
* a never-expiring OAuth access token
**/
if(isset($_GET['error'])) {
echo "There was an error. Dwolla said: {$_GET['error_description']}";
}
else if(isset($_GET['code'])) {
$code = $_GET['code'];
$token = $Dwolla->requestToken($code);
if(!$token) { $Dwolla->getError(); } // Check for errors
else {
session_start();
$_SESSION['token'] = $token;
echo "Your access token is: {$token}";
} // Print the access token
}
TL;DR - No, that's not how OAuth works
The whole point of the OAuth scheme is authentication on the website of the service that you want to use, in this case, Dwolla. By forcing the user to go to their page it ensures a few things:
The user is made aware that they are using an external service whose terms of service may be different than your application
The user is made aware of the features requested by your application for that service. In dwolla's case there are different levels of functionality that can be requested by your application including transferring of money, so it's important that your users are aware of that!
You can read up more on OAuth at http://oauth.net/
I am currently using LightOpenID to allow users to log into my site, where I can automatically extract their username and email address:
$openid->required = array('namePerson/first', 'namePerson/last', 'contact/email');
$openid->identity = 'https://www.google.com/accounts/o8/id';
Here I am using the parameters namePerson/first, namePerson/last, and contact/email.
I understand that inorder to get a list of user contacts, I have to use the feed:
https://www.google.com/m8/feeds
However, I can't seem to figure out which parameters I need to use for this?
If I remove the paramter line altogether, I just get an empty array back.
Can anyone please help me figure out which parameters I need to get the contacts?
Here is the current code I have:
<?php
require '/var/www/libraries/openid.php';
try {
$openid = new LightOpenID;
if(!$openid->mode) {
//$openid->required = array('gd/fullName');
$openid->identity = 'https://www.google.com/m8/feeds/contacts/oshirowanen.y%40gmail.com/full';
header('Location: ' . $openid->authUrl());
exit;
} elseif($openid->mode == 'cancel') {
echo "cancelled";
exit;
} else {
if ( $openid->validate() ) {
$returned = $openid->getAttributes();
print_r($returned);
exit;
} else {
echo "something is wrong";
exit;
}
}
} catch(ErrorException $e) {
echo $e->getMessage();
}
?>
You can't do that with LightOpenID because it only implements the OpenID protocol.
You will need the OAuth (2.0) protocol to do that. Per the docs:
About authorization protocols
We recommend using OAuth 2.0 to authorize requests.
If your application has certain unusual authorization requirements,
such as logging in at the same time as requesting data access (hybrid)
or domain-wide delegation of authority (2LO), then you cannot
currently use OAuth 2.0 tokens. In such cases, you must instead use
OAuth 1.0 tokens and an API key. You can find your application's API
key in the Google API Console, in the Simple API Access section of the
API Access pane.
Per the docs:
Retrieving all contacts
To retrieve all of a user's contacts, send an authorized GET request
to the following URL:
https://www.google.com/m8/feeds/contacts/{userEmail}/full
With the appropriate value in place of userEmail.
Note: The special userEmail value default can be used to refer to the
authenticated user.
It should be possible as per the docs:
https://developers.google.com/accounts/docs/OpenID
OpenID+OAuth Hybrid protocol lets web developers combine an OpenID request with an OAuth
authentication request. This extension is useful for web developers who use both OpenID and OAuth, particularly in that it simplifies the process for users by requesting their approval once instead of twice.