Update 7/13/12:
Fixed IE Bug by enclosing popup URL access block within try/catch (tested in IE9)
1. Theory
Open ID
OpenID is an open standard that describes how users can be authenticated in a decentralized manner, eliminating the need for services to provide their own ad hoc systems and allowing users to consolidate their digital identities. – Wikipedia
Authentication
Authentication is the mechanism whereby systems may securely identify their users.
Authorization
Authorization, by contrast, is the mechanism by which a system determines what level of access a particular authenticated user should have to secured resources controlled by the system.
2. Google Accounts Authentication and Authorization
Step 1: Registering the Application
- Register an application in Google APIS Console @ https://code.google.com/apis/console.
- Goto API Access page.
- Create a client ID in that page by selecting Web Application and set Redirect URL to some blank page in your web site. Just an empty page is enough. Lets say the Redirect URL (URL of that empty page) be www.example.com/oauth/
- Note down your Client ID.
- Enough theory we will get into coding.
Step 2: Basic Web Page setup
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
var OAUTHURL = 'https://accounts.google.com/o/oauth2/auth?';
var VALIDURL = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=';
var SCOPE = 'https://www.googleapis.com/auth/userinfo.profile';
var CLIENTID = '433322211111.apps.googleusercontent.com';
var REDIRECT = 'http://localhost:8888/MAMP/html5/oauth/'
var TYPE = 'token';
var _url = OAUTHURL + 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE;
function login() {
}
</script>
</head>
<body>
<a href='#' onClick='login();'> click here to login </a>
<div id='uName'>Welcome </div>
<img src='' id='imgHolder'/>
</body>
</html>
- OAUTHURL – This is the google end point to get access token
- VALIDURL – This URL is to validate the access token.
- SCOPE – This variables refers to various resources / services(APIs) we would like to access which can include Analytics API, Youtube API, Blogger API. Before we access them here, the corresponding API access should be turned on Google APIS Console’s ‘Services’ page. Since we just want basic user’s info our scope is https://www.googleapis.com/auth/userinfo.profile
- CLIENTID – This is ID that you noted down in Step1
- REDIRECT – This is the URL of the empty page that you mentioned in Google APIS Console.
- TYPE – its always token, i suppose.
Step 3: Authentication and Authorization in popup
function login() {
var win = window.open(_url, "windowname1", 'width=800, height=600');
var pollTimer = window.setInterval(function() {
try {
console.log(win.document.URL);
if (win.document.URL.indexOf(REDIRECT) != -1) {
window.clearInterval(pollTimer);
var url = win.document.URL;
acToken = gup(url, 'access_token');
tokenType = gup(url, 'token_type');
expiresIn = gup(url, 'expires_in');
win.close();
validateToken(acToken);
}
} catch(e) {
}
}, 100);
}
function validateToken(token) {
}
//credits: http://www.netlobo.com/url_query_string_javascript.html
function gup(url, name) {
name = name.replace(/[[]/,"\[").replace(/[]]/,"\]");
var regexS = "[\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( url );
if( results == null )
return "";
else
return results[1];
}
What is access token?
Access Token is a string returned by OAuth server after successful authorization. For all further API requests, the access token need to be passed.
Step 4: Validating Access token
function validateToken(token) {
$.ajax({
url: VALIDURL + token,
data: null,
success: function(responseText){
getUserInfo();
},
dataType: "jsonp"
});
}
Replace the empty validateToken with the function above. Its a very straight forward ajax call using jquery to the validation URL. We are passing our access token to the Validation URL. On success, we call another function, getUserInfo() which retrieves the user’s information.
Step 5: Retrieving User Info
function getUserInfo() {
$.ajax({
url: 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' + acToken,
data: null,
success: function(resp) {
user = resp;
console.log(user);
$('#uName').append(user.name);
$('#imgHolder').attr('src', user.picture);
},
dataType: "jsonp"
});
}
Its another ajax call to get the user info. Access Token is passed along with the call. On successful response, the placeholder HTML elements are updated with appropriate user’s name and picture.
Step 6: Logging out
Logging out of the session seemed to be a trivial one. Quick googling revealed, just pointing to http://accounts.google.com/Logout does the job. So I wrote an AJAX call that POSTed to the logout URL. But it always returned some error. So I opened up the URL in a popup window and this does the job perfectly, except that there is no way for me to close the pop once the session is logged out ,since I cant access URL of popup window as the domain is google.com (cross-domain issues) and also there is no way I could redirect to my domain after logging out.
I was scratching my head on what to do and this thread on SO came to the rescue. The point is to make an iframe and load the logout url in that frame and then hiding the iframe by setting its display style to none as follows:
<!-- inside body tag -->
<a href="#" style="display:none" id="logoutText" target='myIFrame' onclick="myIFrame.location='https://www.google.com/accounts/Logout'; startLogoutPolling();return false;"> Click here to logout </a>
<iframe name='myIFrame' id="myIFrame" style='display:none'></iframe>
//inside script tag
function startLogoutPolling() {
$('#loginText').show();
$('#logoutText').hide();
loggedIn = false;
$('#uName').text('Welcome ');
$('#imgHolder').attr('src', 'none.jpg');
}
But still there is a catch. This code allows the user to login again immediately after the logout procedure is started. So when you click fast enough on login immediately after you clicked on logout, then there is a high chance that you get logged into previous session automatically without asking for user credentials. This could be fixed by adding some delay (say 2 seconds) and allowing user to login only after that delay.
Full Code goes Here:
<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<script>
var OAUTHURL = 'https://accounts.google.com/o/oauth2/auth?';
var VALIDURL = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=';
var SCOPE = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email';
var CLIENTID = '716569014051.apps.googleusercontent.com';
var REDIRECT = 'http://www.gethugames.in/proto/googleapi/oauth/'
var LOGOUT = 'http://accounts.google.com/Logout';
var TYPE = 'token';
var _url = OAUTHURL + 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE;
var acToken;
var tokenType;
var expiresIn;
var user;
var loggedIn = false;
function login() {
var win = window.open(_url, "windowname1", 'width=800, height=600');
var pollTimer = window.setInterval(function() {
console.log(win);
console.log(win.document);
console.log(win.document.URL);
if (win.document.URL.indexOf(REDIRECT) != -1) {
window.clearInterval(pollTimer);
var url = win.document.URL;
acToken = gup(url, 'access_token');
tokenType = gup(url, 'token_type');
expiresIn = gup(url, 'expires_in');
win.close();
validateToken(acToken);
}
}, 500);
}
function validateToken(token) {
$.ajax({
url: VALIDURL + token,
data: null,
success: function(responseText){
getUserInfo();
loggedIn = true;
$('#loginText').hide();
$('#logoutText').show();
},
dataType: "jsonp"
});
}
function getUserInfo() {
$.ajax({
url: 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' + acToken,
data: null,
success: function(resp) {
user = resp;
console.log(user);
$('#uName').text('Welcome ' + user.name);
$('#imgHolder').attr('src', user.picture);
},
dataType: "jsonp"
});
}
//credits: http://www.netlobo.com/url_query_string_javascript.html
function gup(url, name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\#&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( url );
if( results == null )
return "";
else
return results[1];
}
function startLogoutPolling() {
$('#loginText').show();
$('#logoutText').hide();
loggedIn = false;
$('#uName').text('Welcome ');
$('#imgHolder').attr('src', 'none.jpg');
}
</script>
</head>
<body>
<a href='#' onClick='login();' id="loginText"'> Click here to login </a>
<a href="#" style="display:none" id="logoutText" target='myIFrame' onclick="myIFrame.location='https://www.google.com/accounts/Logout'; startLogoutPolling();return false;"> Click here to logout </a>
<iframe name='myIFrame' id="myIFrame" style='display:none'></iframe>
<div id='uName'></div>
<img src='' id='imgHolder'/>
</body>
</html>
Good tutorial …keep it up
First of all Thanks for presenting this code… super materiel…
Thanks allot………..
thanks Sankar G(ji)
especially for pointing out that & problem… fixed it now
Thanks for the code, But i am getting "Access denied error" in IE Only.
Do you have any idea how to solved the same?
Hi,
Nice post.
Can you please tell me how to fetch email and accesstoken
@(Thalaiva)Rajanikath Thota:
To get email, just add the scope 'userinfo.email' as below:
var SCOPE = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email';
Then you will get the Email ID, in response to the userinfo call.
@.Net(C#): I am not sure what the problem is. I will check and get back to you asap.
Note that IE chokes when using that popup… Once you submit the auth form, IE "can't" display the page :/
yeah its not working in IE. I guess its with retrieving the access token from pop-up URL, not sure thought… been busy with some works, will check and post a solution soon
IE chokes when authenticating through a simple URL redirection. The pop-up is not the issue (I guess).
Appreciate your great effort.
not that this isn't AWESOME but a complete example would have a logout button too
Does not work in IE.
a very nice and clear post. it really worked fantastic.. thanks
Hi,
Thanks for the post. I have used it it works perfect for my application.
I need to users to be logged out of google when they logout of my application. How do I achieve this? Please help.
Thanks to all for your appreciation. I added logout functionality to the code and updated the post appropriately.
I dont have Window in both home and office, thats why I cant look into IE issue. But will try to fix it somewhere this weekend and update the post.
Thanks
Thanks for the tutorial.
Your Demo is not working in Safari. It returns “Welcome undefined”.
I’m using OSX 10.6.8. The Demo is working in Firefox and Chrome.
Fixed the bug in Safari. It was a missing slash at the end of REDIRECT url: ‘http://localhost:8888/MAMP/web-prototypes/googleapi/oauth/’
Thanks Bhriv for pointing it out
Saiyasodharan R, I posted this same question in stackoverflow.
If I get access token the way you suggest, which will make it valid in parent window, can I then make API calls to google apps using the google-api-php-client library?
Thank you,
Veronica
@Veronica: Since you are using PHP library, I suggest you to authorize using the functions provided by that library itself rather than falling back to JS for authentication. I believe that is possible. and I replied the same in SO.
I have set up a a Project in the Google APIs Console.
I have followed your example.
I have set up client ID.
I have created a blank page in root directory of Tomcat, and set the corresponding redirect uri
Redirect URIs: https://localhost:8080/test2.html
I get this error:
Secure Connection Failed
An error occurred during a connection to localhost:8080.
SSL received a record that exceeded the maximum permissible length.
(Error code: ssl_error_rx_record_too_long)
The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.
Please contact the website owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.
What can be the reason????
Thanks much in advance!!!!
I have put it onto remote container and it worked
DDD
I think I had to configurate my Tomcat
Now, how can it work in IE?
If you fixed it in IE, could you please post it. Thanks you!!!!!!
updated the code already with the IE bug fix, forgot to remove the IE warning though. Removed it now
I don’t know how I would ever get stuff working like this without people like you! Thanks so much. You saved hours/days of work.
When I redirect to my blank page, I get the buttons, allow access/no thanks. But when I run with your redirect URL and client ID, it doesn’t ask for allow access. Did I do something wrong with my client registration?
“run with your redirect URL” ?? are you also developing in MAMP as I do ? as long as the redirect path given in API console and the actual paths we use match, it should work…
I use Apache on windows and IE. Your html code as downloaded works fine. When I change the redirect URL and client ID to my own, I get the allow access question. But with yours I don’t and the token is printed on the window title.
As I said already, the actual Redirect URL should match the one you given in the API console and obviously my client ID and yours will be different. So, it wont work out for you with my URL and client ID…
Example works fine but after login google i cant redirect to my url..i want to redirect::
localhost/oauth/index.php and want every login user on different redirect?? its possible?? if Yes than How??
Thank in advance..!
in `getUserInfo` function, get the user’s name and then make a redirect like `window.location.href = “localhost/profile/” + user.name;`
i am using this code but redirect url open in popup but poup not close in crome browser please help me
Can you check the console logs and see if any exception is thrown ?
yes console log display error
cannot read property ‘URL’ undefined
and same problem in IE Browser Pls Help
Its working fine for me in Chrome v22 and I also checked it to be working in IE8. Can you tell me your browser versions ?
I have also struggled with the issue, until realizing that my code page was in sub domain of local host, and the redirect page was under localhost (google do not allow for some reason the redirect url to be in a subdomain of localhost). once moving the source page to localhost (to be in the same domain of the redirect page), all was ok.
it is a sequrity issue to access info from different domains I guess (although it is just domain and subdomain)
With this method, you don’t have to give to Google any secret key. Isn’t it a problem?
I could take your code, modify it, and for every user who has accepted to use your app, access to their data because Authentification would be invisible since user already have accepted the app.
With this testApp, maybe it’s not a real problem, but imagine you do the same thing with a well known app. If I see “well known app wants to access to your account”, if I use well known app myself, I will accept the access, and a totally unknown developer will be able to play with my data.
To sum up, the absence of control of app identity scares me a lot, and I’m surprised that Google don’t talk about it in this page:
https://developers.google.com/accounts/docs/OAuth2UserAgent
It seems to me a bit too big to believe in. Where am I wrong ?
I guess REDIRECT URI serves this purpose. After the auth process, google redirects to the URI in ‘my domain’ that I defined in Google apis console, which you cant access from any random domain because of cross domain policy restrictions.
can we display user information on the REDIRECT page?How?
yes very much… Just move the `validateToken` and `getUserInfo` to the redirect page..
It is not working in IE 9 can you please provide a fix it’s just stops after popup
Can you tell me if you are getting any errors in console? I am stuck between mac in office and Ubuntu in home…
I think this is one of the most significant info for me. And i am glad reading your article. But should remark on few general things, The web site style is ideal, the articles is really great : D. Good job, cheers
Great Post!
But how come if i test your code locally with my API data it keeps on showing the “Request for permission” page?
Your example application works perfect, it only ask for permission once. And afterwards it always delivers the access token (until the token expires)
hmm… not sure, can you mail me your code ?
Nice one thanks for sharing keep it up
can we do it only using javascript i mean without jquery
if yes please give me suggestion
Cheers
Anand Neema
I am making all AJAX calls with jQuery. You can use plain XMLHTTPRequest to do the same in javascript. Please refer: http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp
I see the code the code is nice and i am very happy its working fine but i want more information Like users bithdate,location etc there is any parameter to access that
Enable Google+ API Services in Google API Console and use people GET to access user details. Refer: https://developers.google.com/+/api/latest/people/get
Hello,
I am getting this error
Unable to connect
Firefox can’t establish a connection to the server at localhost.
i think this is sumthing to do with redirect URL.
if i want to run my app locally..then which URL should i mention in the API console.?
Thanks
It simply `localhost` as in the code. Try giving in the PORT Numbers.
And the thing is that.. i am making a chrome extension which uses oauth to access gmail api…so if u know sumthing..abt it..then plz help…thanks
No idea about making Extensions.. But I am eager to try it.. Maybe drop me a mail regarding the same. We will discuss
Is it necessary to hide the “redirecturl” for the user once it is successfull. OR is there any problem in showing the right “redirecturl”
There is no problem in showing the Redirect URL…
Do u have any idea of using IMAP with oauth 2.0 to get gmail attachment list in javascript?Thanks
Sorry no..
Hi,
Great turorial by the way. I’m very new to JavaScript, ajax and so on. Was just wondering, on a general development level how to get this working on my local machine.
I’ve followed the example and redirected to an existing site. Which works with the AccessToken etc appearing in the URL, but the popup doesn’t close and the browser window running your code doesn’t get the user info – presume this is due to using some random redirect URL that’s different to where the original page is located.
So my question is, what should I set the redirect URL to (in the API console and the HTML file) in order to run this from local file on my hard drive? Do I need to setup localhost in order to get this working? or is there an easier way ?
Yes, a localhost is mandatory. Google servers cant redirect to a file which is in your local filesystem. They need to be accessed via http, in order for the redirection to work.
Try WAMP / MAMP / LAMP, which is very easy to install and work with.
i have posted a quick solution to this problem in the stackoverflow post (now is the last =D ):
http://stackoverflow.com/questions/4202161/google-account-logout-and-redirect/14831349#14831349
bye.
Thanks a lot…. i was stuck with this problem from last few days…keep it up
I have tried this in ie but it is giving null for win how to resolve that pls tell me
Is there any way to get this to work on an iPad or mobile phone. Can the Google login open in it’s self instead of popup box?
I faced the problem to access the document property because of security , Actually If you miss “www” in any of url then it will not work… Fix it that
I just finished using the material herein to implement it on my app. Thank you very much for your contribution.
Regards
Rodrigo