Client Side Twitter Login with Angular 1.x and OAuth.io

Authentication using the OAuth.io service on the client side

First off thank you to Preetish Panda for his tutorial on oauth.io. You can find that tutorial here.

===============

SOURCE CODE for this tutorial.

DEMO of async twitter authentication

Getting started

Create a static bare-bones angular app. There is an angular.js starter app here.

1
2
3
$ git clone git@github.com:connor11528/angular-starter.git
$ cd angular-starter
$ python -m SimpleHTTPServer

If you’re using git and want to push this to your own repo add it as a remote:

1
2
3
$ git remote rm origin
$ git remote add origin <your_remote_url>
$ git push origin master

Create an app with twitter

We are going to use twitter to handle our authentication. That means “Log in with twitter”. In order to do that we need to register an application with the good folks at twitter.

Go here: https://apps.twitter.com/app/new

For the record you also need to have a mobile phone associated with your twitter profile before you can create an application. Go to settings/mobile to add one. https://oauth.io/auth is our Callback URL. For the website URL I am using my custome domain hosted by Github Pages. It is free with your github account and is a good tool and way to showcase your work.

Create auth.io account

OAuth is an open protocol for authorization across applications. OAuth.io is a company that makes using the OAuth protocol mad simple. The two are different. We can make 2000 API calls per month for free using oauth.io. If we make 20,000 API calls per month using oauth.io it costs $20.

To use oauth.io to handle authentication create an account with them: https://oauth.io/signup

On the dashboard click “Integrated APIs” and add the twitter app’s credentials. The first one is “Consumer Key (API Key)” and the next field is “Consumer Secret (API Secret)” which both come from the “Keys and Access Tokens” panel on your twitter app registration page.

Save changes and you should be able to successfully “Try Auth”.

Enough setup, let’s code

We’re going to use the oath.js library. Download it from their github repo and then link to the script:

<script src='js/lib/oauth.js'></script>

After we initialize our main angular app in js/app.js add a constant with your oauth.io Public Key.

We’re also gunna define routes using ui-router:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var app = angular.module('angular-starter', [
'ui.router'
]);
app.constant('OAUTH_PUBLIC_KEY', 'p2edLIP-Hu5-VvhkJN1T_Ncba0M');
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise("/");
$stateProvider
.state('home', {
url: "/",
templateUrl: "templates/main.html",
controller: 'MainCtrl'
});
});

Then we’ll define the template. It is a simple navbar with sign in, hello message and log out buttons. We show them conditionally based on a $rootScope value we’ll get to in a second. ng-if hides or shows based on if $scope.currentUser is true or false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class='row'>
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="#">oauth.io-example</a>
</div>
<div>
<ul class="nav navbar-nav pull-right">
<li>
<a href ng-if='!currentUser' ng-click="signIn()">Sign in with twitter</a>
</li>
<li>
<a href ng-if='currentUser'>Hello {{currentUser.name}}</a>
</li>
<li>
<a href ng-if='currentUser' ng-click="signOut()" id="signOut">Sign Out</a>
</li>
</ul>
</div>
</nav>
</div>
<div class='row'>
<pre{{ currentUser | json }}</pre>
</div>

Next we’ll setup MainCtrl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
app.controller('MainCtrl', function($scope, oauth){
$scope.user = {};
//when the user clicks the connect twitter button, the popup authorization window opens
$scope.signIn = function() {
oauth.connectTwitter();
};
//sign out clears the OAuth cache, the user will have to reauthenticate when returning
$scope.signOut = function() {
oauth.clearCache();
};
//if the user is a returning user, hide the sign in button and display the tweets
if (oauth.isReady()) {
// gets data and updates $rootScope
oauth.getUserData();
}
});

All of the work will really be happening in our oauth service.

oauth service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
app.service('oauth', function(OAUTH_PUBLIC_KEY, $q, $http, $rootScope){
var authorizationResult = false;
return {
initialize: function() {
$rootScope.currentUser = false;
//initialize OAuth.io with public key of the application
OAuth.initialize(OAUTH_PUBLIC_KEY, {
cache: true
});
//try to create an authorization result when the page loads,
// this means a returning user won't have to click the twitter button again
authorizationResult = OAuth.create("twitter");
},
isReady: function() {
return (authorizationResult);
},
connectTwitter: function() {
var deferred = $q.defer();
var self = this;
OAuth.popup("twitter", {
cache: true
}, function(error, result) {
if (!error) {
// update token
authorizationResult = result;
// get data from twitter
self.getUserData();
deferred.resolve();
} else {
// shit shit fire ze missiles
deferred.reject();
console.error('could not connect to twitter');
$rootScope.currentUser = false;
}
});
return deferred.promise;
},
getUserData: function(){
var oauth_token = this.isReady();
if(oauth_token){
// get user's data from token
oauth_token.me().done(function(currentUser){
$rootScope.currentUser = currentUser;
// run the digest cycle to update scope with the
// data we got from .me() oauth.io method
$rootScope.$apply();
});
} else {
console.error('Cannot get user data. No one is logged in!');
return false;
}
},
clearCache: function() {
// log them out and clear the scope
OAuth.clearCache('twitter');
$rootScope.currentUser = false;
}
};
});

In the getUserData function I get the logged in user’s information via .me() otherwise their info is only the token. We update the $rootScope and then have to run the digest cycle again with $apply() to let angular know about the changes.

This is not perfect. The client could change the value of $rootScope and nothing would really be hidden. This does not really secure our app but it does get data from twitter for us. oauth.io has hundreds of services that we could get information from. Log in to the dashboard, click “Integrated APIs” then “Add APIs” and type any provider you can think of. If we wanted to associate our own data with a user’s account we would need our own database and server, or we could use firebase

Here is the completed DEMO.

Add your github url (<username>.github.io) to “Domains & URLs whitelist” on the oauth.io dashboard homepage and you can have a live site also.

final SOURCE CODE. Give it a star!