I have a few popular Oauth related posts on my blog. I have one pertaining to Oauth 1.0a, and I have one on the topic of Oauth 2.0 for use in mobile application development. However, I get a lot of requests to show how to accomplish an Oauth 2.0 connection in a web browser using only JavaScript and AngularJS.
We’re going to better explore the process flow behind Oauth 2.0 to establish a secure connection with a provider of our choice. In this particular example we’ll be using Imgur because I personally think it is a great service.
Before we begin, it is important to note that this tutorial will only work with providers that offer the implicit grant type.
Oauth Implicit Grant Type via OauthLib:
The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI. These clients are typically implemented in a browser using a scripting language such as JavaScript.
Unlike the authorization code grant type, in which the client makes separate requests for authorization and for an access token, the client receives the access token as the result of the authorization request.
You’ll know the provider supports the implicit grant type when they make use of response_type=token
rather than response_type=code
.
So there are going to be a few requirements to accomplish this in AngularJS:
With that said, let’s go ahead and create our project to look like the following:
project root
templates
login.html
secure.html
js
app.js
index.html
oauth_callback.html
The templates/login.html page is where we will initialize the Oauth flow. After reaching the oauth_callback.html page we will redirect to the templates/secure.html page which requires a successful sign in.
Crack open your index.html file and add the following code:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.min.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="example">
<div ui-view></div>
</body>
</html>
Now it is time to add some very basic HTML to our templates/login.html and templates/secure.html pages:
<h1>Login</h1>
<button ng-click="login()">Login with Imgur</button>
The above code goes in the templates/login.html page and the below code goes in the templates/secure.html page:
<h1>Secure Web Page</h1>
<b>Access Token: </b> {{accessToken}}
Not much left to do now. Open your js/app.js file and add the following AngularJS code:
var example = angular.module("example", ['ui.router']);
example.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginController'
})
.state('secure', {
url: '/secure',
templateUrl: 'templates/secure.html',
controller: 'SecureController'
});
$urlRouterProvider.otherwise('/login');
});
example.controller("LoginController", function($scope) {
$scope.login = function() {
window.location.href = "https://api.imgur.com/oauth2/authorize?client_id=" + "CLIENT_ID_HERE" + "&response_type=token"
}
});
example.controller("SecureController", function($scope) {
$scope.accessToken = JSON.parse(window.localStorage.getItem("imgur")).oauth.access_token;
});
We are first going to focus on the login
method of the LoginController
. Go ahead and add the following, pretty much taken exactly from the Imgur documentation:
$scope.login = function() {
window.location.href = "https://api.imgur.com/oauth2/authorize?client_id=" + "CLIENT_ID_HERE" + "&response_type=token"
}
This long URL has the following components:
Parameter | Description |
---|---|
client_id | The application id found in your Imgur developer dashboard |
response_type | Authorization grant or implicit grant type. In our case token for implicit grant |
The values will typically change per provider, but the parameters will usually remain the same.
Now let’s dive into the callback portion. After the Imgur login flow, it is going to send you to http://localhost/oauth_callback.html because that is what we’ve decided to enter into the Imgur dashboard. Crack open your oauth_callback.html file and add the following source code:
<html>
<head>
<script>
var callbackResponse = (document.URL).split("#")[1];
var responseParameters = (callbackResponse).split("&");
var parameterMap = [];
for(var i = 0; i < responseParameters.length; i++) {
parameterMap[responseParameters[i].split("=")[0]] = responseParameters[i].split("=")[1];
}
if(parameterMap.access_token !== undefined && parameterMap.access_token !== null) {
var imgur = {
oauth: {
access_token: parameterMap.access_token,
expires_in: parameterMap.expires_in,
account_username: parameterMap.account_username
}
};
window.localStorage.setItem("imgur", JSON.stringify(imgur));
window.location.href = "http://localhost/index.html#/secure";
} else {
alert("Problem authenticating");
}
</script>
</head>
<body>Redirecting...</body>
</html>
If you’re familiar with the ng-cordova-oauth library that I made, you’ll know much of this code was copied from it. Basically what we’re doing is grabbing the current URL and parsing out all the token parameters that Imgur has provided us. We are then going to construct an object with these parameters and serialize them into local storage. Finally we are going to redirect into the secure area of our application.
In order to test this we need to be running our site from a domain or localhost. We cannot test this via a file:// URL. If you’re on a Mac or Linux machine, the simplest thing to do is run sudo python -m SimpleHTTPServer 80
since both these platforms ship with Python. This will run your web application as localhost on port 80.
A video version of this article can be seen below.