Introduction
With most modern applications now using HTML and JavaScript, it is very much a wise idea so you keep up with the current trend. Some major entities provide APIs for various reasons which include client authentication and authorization. A popular feature being used for authentication in websites today is "Single Sign-on". This give users the ability to sign into your website using other identity providers especially those from social media websites. This article will demonstrate a simple way of integrating this feature for three major identity providers into your website using purely JavaScript.
Background
In order to utilize the API from the Identity providers, you are required to create an application on their websites which will give you an API key to use in the application.
Using the Code
If you are not into long reading, you may go ahead and download the source files and use/modify as you please.
Firstly, we include some files in the head of our HTML page.
<!--
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.1.0.js"></script>
<!--
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
In recent times, Twitter has deprecated the use of solely client side authentication which may cause some developers to cringe. However, thanks to YUI (an API provided by Yahoo!) we are able so simulate a server side request to Twitter using JavaScript. So we also include the YUI library in the head.
<!--
<script type="text/javascript"
src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script>
We now create three DOM elements to trigger the requests. These elements could be any of your choice.
<div id="fbLogin" onclick="">Facebook</div>
<div id="twitterlogin">Twitter</div>
<div id="googlelogin">Google</div>
Now let us look into the script. We'll start with the Facebook log in.
Facebook
The first function we'll create is one to make the initial request to Facebook oAuth API sending the client ID (given in your Facebook app), the redirect URL (must be the same as the one registered in your app), as well as the response type (in this case an access token). The access token is needed to show that the user is authenticated and it will be used to connect to the Facebook graph API and access the user's profile information.
var appID = <YOUR CLIENT ID>;
function fbLogin() {
var path = 'https://www.facebook.com/dialog/oauth?';
var queryParams = ['client_id=' + appID,
'redirect_uri=' + window.location,
'response_type=token'];
var query = queryParams.join('&');
var url = path + query;
window.location.replace(url);
}
The response will be a redirect to your website with the access token attached as a hash string "#access_token=.......". To use the access token we now need a function to check for the access token in the URL. The function will also make a request to the Facebook graph API sending the access token and a callback function which will receive the user information as a parameter.
function checkFbHashLogin() {
if (window.location.hash.length > 3) {
var hash = window.location.hash.substring(1);
if(hash.split('=')[0] == 'access_token')
{
var path = "https://graph.facebook.com/me?";
var queryParams = [hash, 'callback=displayUser'];
var query = queryParams.join('&');
var url = path + query;
var script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
}
}
}
Now in the third step we'll use the callback function to utilize the user information as we see fit.
function displayUser(user) {
setTimeout(function () { }, 1000);
if (user.id != null && user.id != "undefined") {
}
else {
alert('user error');
}
}
Lastly, we just need to trigger the function call and also we would have to run the function to check the hash string on page load.
$(function () {
checkFbHashLogin();
$('#fbLogin').click(function () {
fbLogin();
});
})
We have now completed the Facebook authentication.
Google
In this first step, I'll just give the functions while the comments in the code will explain what the functions does. As stated earlier we need to have our client ID and in the case of Google, we have to utilize the API key for the application.
var clientId = <YOUR CLIENT ID>;
var apiKey = <YOUR API KEY>;
var scopes = 'https://www.googleapis.com/auth/plus.me';
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
makeApiCall();
}
}
function handleAuthClick(event) { gapi.auth.authorize({ client_id: clientId,
scope: scopes, immediate: false }, handleAuthResult);
return false;
}
function makeApiCall() {
gapi.client.load('plus', 'v1', function () {
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function (resp) {
});
});
}
$(function () {
var authorizeButton = document.getElementById('googlelogin');
authorizeButton.onclick = handleAuthClick;
})
That completes the Google authentication.
Twitter (Old version of twitter API)
This method will give some errors but it can give a simple overview
As mentioned before, the Twitter API does not allow purely client side authentication. For this reason the YUI library is used. This library makes use of the Yahoo Query Language (YQL) to make server side requests to the Twitter API.
For example, one of the the YQL statements which will be used in the application is
select * from twitter.oauth.requesttoken where oauth_callback="<YOUR WEBSITE URL>";
As you can see the select statement is just like any other query language select statement. The condition parameter for the select statement (oauth_callback
) is the callback URL you would have registered with your Twitter app. Because we are selecting where the URLs match, we are not required to use the client ID. Since we are using JavaScript, we can just use window.location
to get the current URL for the query (already taken care of in the code). In essence we need not worry about YUI and the YQL queries. Hence, let us now look at the implementation of the YUI library and how it is used to make the Twitter API calls.
The first step is initializing the YUI object. Within this object we are going to set the modules that will be used and their location. In our case we are using the Twitter and YQL modules.
YUI({
combine: false,
filter: "raw",
debug: false,
modules: {
'Twitter': {
fullpath: 'js/twitter.js'
},
'myYQL': {
fullpath: 'js/yql.js',
requires: ['jsonp', 'jsonp-url']
}
}
})
In the next step, we'll tell the YIU library which components we want to use from its repository and also provide a callback function. We do this by calling the YUI "use' function which is appended to the YUI object after initialization.
YUI({
...
}).use('Twitter', 'gallery-storage-lite', 'myYQL', 'node', "event", function (Y) {});
The callback function will be executed right after the YUI library is initialized and components, therefore we'll put all the code to handle the authorization for the Twitter API in this function. The first thing to do is to get the element that will trigger the Twitter authorization and binding its click event with a function. This function will make the first API call to get oAuth request token and secret. These will be passed in a query string to the Twitter authenticate API and the oAuth token verifier returned in like manner.
var twtBtn = Y.one('#twitterlogin');
twtBtn.on('click', function (e) {
Y.Twitter.call({ type: "request_token" }, function (tokens) {
Y.log("step 1");
Y.log(tokens);
Y.StorageLite.setItem('oauth_token', tokens.oauth_token);
Y.StorageLite.setItem('oauth_token_secret', tokens.oauth_token_secret);
window.setTimeout(function () {
window.location = "https://twitter.com/oauth/authenticate?oauth_token=" +
tokens.oauth_token + "&oauth_token_secret=" + tokens.oauth_token_secret;
}, 10);
});
});
The next few steps are combined in nested calls and responses until we get the final response. We first check the query string to get the oAuth token verifier. The token and verifier are then passed to the YUI Twitter call to get the access tokens. Finally the access tokens are sent in a call to retrieve the user's information.
if (getQueryStringParameter('oauth_token')) {
Y.StorageLite.setItem('oauth_token', getQueryStringParameter('oauth_token'));
Y.StorageLite.setItem('oauth_verifier', getQueryStringParameter('oauth_verifier'));
Y.Twitter.config({
oauth_token: getQueryStringParameter('oauth_token'),
oauth_token_secret: getQueryStringParameter('oauth_token_secret')
});
Y.Twitter.call({ type: "access_token" }, function (tokens) {
Y.Twitter.config({
oauth_token: tokens.oauth_token,
oauth_token_secret: tokens.oauth_token_secret
});
Y.Twitter.call({ type: "credentials" }, function (user) {
Y.Twitter.config({
screen_name: user.screen_name,
user_id: user.id
});
});
});
}
That would complete all the requests for the Twitter authentication component.
function getQueryStringParameter(key, queryString) {
var queryString = queryString || window.location.href;
key = key.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex = new RegExp("[\\?&]" + key + "=([^&#]*)");
var qs = regex.exec(queryString);
if (qs)
return qs[1];
else
return false;
}
Points of Interest
The utilization of single sign-on is rapidly growing and many major websites such as Yahoo! and Hotmail allow users identity for single sign-on. For example, when configuring your Google API app you are able to tie other providers with your Google API key. Also note that all requests should initiate from the domain that is registered in each respective Identity provider's application and you will be required to use a valid domain and website URL. For this reason, the application will not work successfully from your localhost.