Using An Oauth 2.0 Service With Ionic Framework

Many APIs such as Google, Twitter, and Facebook require Oauth in order to use. This can get tricky when it comes to mobile because authorization must happen externally in a web browser. To our advantage, we can handle Oauth 2.0 using the InAppBrowser plugin for Apache Cordova.

Basic instructions on using the InAppBrowser with Ionic Framework can be found in one of my earlier blog posts. If you’re looking to use Oauth in an Ionic 2 application, visit here, otherwise proceed with Ionic Framework 1.

Start by picking an API you’d like to use. For this example let’s use Google. If you haven’t already, you need to create a new project using the Google Developer Console. In the credentials section you’ll need to choose Oauth 2.0 and create a client id for a web application. The most important part in this process is to set the redirect / callback url as http://localhost/callback. If your API console doesn’t allow localhost for the callback, choose some other dummy URL.

Now for the fun part. Assuming you’ve installed the InAppBrowser plugin like described in my previous tutorial, crack open your app.js file as we’re going to add some token logic.

Google’s Oauth 2.0 consists of acquiring a request token and an access token. Your users will get a request token when authorizing the app login, and then the request token will be exchanged for an access token.

var ref = window.open('https://accounts.google.com/o/oauth2/auth?client_id=' + clientId + '&redirect_uri=http://localhost/callback&scope=https://www.googleapis.com/auth/urlshortener&approval_prompt=force&response_type=code&access_type=offline', '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
    if((event.url).startsWith("http://localhost/callback")) {
        requestToken = (event.url).split("code=")[1];
        ref.close();
    }
});

The above code will open an InAppBrowser with a callback triggered for the load of each page. In particular we will be looking to see if the loaded page is our callback page registered on the Google website. If it is, extract the request token from the URL. You may be wondering what startsWith is. It is a function that must be created for checking the start of strings. Code for this function can be found below:

if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function (str){
        return this.indexOf(str) == 0;
    };
}

With the request token in hand, it must be exchanged for an access token in order to use the Google APIs. The code for getting an access token is as follows:

$http({method: "post", url: "https://accounts.google.com/o/oauth2/token", data: "client_id=" + clientId + "&client_secret=" + clientSecret + "&redirect_uri=http://localhost/callback" + "&grant_type=authorization_code" + "&code=" + requestToken })
.success(function(data) {
    accessToken = data.access_token;
})
.error(function(data, status) {
    console.log("ERROR: " + data);
});

A thing to note about the Google APIs though. The post requests must have a content type of application/x-www-form-urlencoded rather than the default AngularJS JSON content type. You can change the default POST content type by running:

$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

If you’re not using jQuery, you’ll have to format the POST manually by doing param1=value&param2=value.

So let’s look at a more working example. The example will consist of two screens, protected and an unprotected screen. The unprotected screen will have a button for initiating the token request / exchange:

<ion-view ng-controller="LoginController" title="Oauth Login">
    <ion-content>
        <div>
            <div class="padding">
                <button ng-click="login()" class="button button-block button-stable">
                    Sign In
                </button>
            </div>
        </div>
    </ion-content>
</ion-view>

The protected screen will display our access token which is used for all Google API requests:

<ion-view ng-controller="SecureController" title="Oauth Secure">
    <ion-content>
        <div>
            <div class="padding">
                {{accessToken}}
                <button class="button button-block button-stable">
                    Do Something
                </button>
            </div>
        </div>
    </ion-content>
</ion-view>

Ionic Framework Oauth 2.0

An example app.js can be found below which will be responsible for driving the two screens:

var requestToken = "";
var accessToken = "";
var clientId = "client_id_here";
var clientSecret = "client_secret_here";

var exampleApp = angular.module('example', ['ionic'])
    .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');
    });


exampleApp.controller('LoginController', function($scope, $http, $location) {

    $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

    $scope.login = function() {
        var ref = window.open('https://accounts.google.com/o/oauth2/auth?client_id=' + clientId + '&redirect_uri=http://localhost/callback&scope=https://www.googleapis.com/auth/urlshortener&approval_prompt=force&response_type=code&access_type=offline', '_blank', 'location=no');
        ref.addEventListener('loadstart', function(event) {
            if((event.url).startsWith("http://localhost/callback")) {
                requestToken = (event.url).split("code=")[1];
                $http({method: "post", url: "https://accounts.google.com/o/oauth2/token", data: "client_id=" + clientId + "&client_secret=" + clientSecret + "&redirect_uri=http://localhost/callback" + "&grant_type=authorization_code" + "&code=" + requestToken })
                    .success(function(data) {
                        accessToken = data.access_token;
                        $location.path("/secure");
                    })
                    .error(function(data, status) {
                        alert("ERROR: " + data);
                    });
                ref.close();
            }
        });
    }

    if (typeof String.prototype.startsWith != 'function') {
        String.prototype.startsWith = function (str){
            return this.indexOf(str) == 0;
        };
    }

});

exampleApp.controller('SecureController', function($scope, $http) {

    $scope.accessToken = accessToken;

});

Some things to note about the example. The Google scope is for the URL Shortener API. You’ll want to use the correct scope for the API you want to use. For other APIs like Twitter, you may not have a scope to worry about. The InAppBrowser plugin does not work in a PC browser. The callbacks will only trigger on a device.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

Search

Follow Us

Subscribe

Subscribe to my newsletter for monthly tips and tricks on subjects such as mobile, web, and game development.

Subscribe on YouTube

Support This Site