Writing the Ionic app
In the previous part of this blog we finished writing our nodejs server that exposes for time being a single auth route: /auth/facebook
In this part we will create a simple ionic app using their starter kits, and implement the authentication using an angular library called Satellizer created by a talented developer named Sahat Yalkabov you can follow him on his twitter account.
Github for this project: https://github.com/scopsy/node-ionic-jwt
Ionic
Ionic is a great framework to code hybrid applications that allows us to write apps with web languages: HTML, CSS, JS. One of the selling points for me was that Ionic is written on top of AngularJS. The combination between ionic and angular allowing developers to create scalable and fast hybrid apps.
The ionic ecosystem provides you with default navigation layouts and tools that will allow you to create and build applications easily.
Installations
First, we need to install cordova
and ionic
modules from npm. I would sugesst installing them globally.
npm install -g cordova ionic
Cordova?
cordova is the tool that allows you to turn your html and js to a bundled hybrid application which you can then upload to Google Store or Appstore.
It's also used as the bridge allowing you to interact with native phone API's such as: Camera, calendar, gyroscope, geolocation, battery etc...
There are a lot of cordova plugins you can use, and there is an awesome project named ngCordova
that migrated most of the available cordova plugins in to an easy to integrate angular directives. You can check their site here.
So after installing ionic and cordova we can scaffold our app:
ionic start appName sidemenu
Note that we add sidemenu
as the last argument, ionic comes with multiple starter layouts you can use. If you want clean app to start with simply change sidemenu to blank
.
ionic cli will now download and install all the dependencies needed, when finished run ionic serve
from cli. It will launch a web server on port 8100
(It is important that we will update our facebook developers console with the port we are launching the app from).
Installing satellizer.js
As said above we will use satellizer
for our ionic app. It will take core of the auth code generation with facebook.
bower install satellizer --save
satellizer also requires cordova inapp browser plugin in order to work inside your phone.
So we will install it simply by typing cordova plugin add cordova-plugin-inappbrowser
inside our cli.
You will also need cordova-plugin-whitelist
which comes by default with ionic, but if for some reason your unable to communicate with the server from your phone, it may be the problem.
In this tutorial we will only use our app with ionic serve
so you can skip the cordova plugins, but if you plan to take your app and deploy it for test in an actual phone make sure you installed both plugins.
Now open index.html
file located inside the www
folder. This file be the main entry point for our Ionic app.
Here we will add the satellizer plugin under cordova.js
file.
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<script src="lib/satellizer/satellizer.js"></script>
Next, we must add satellizer as an app dependency. Open app.js
located at www/js/app.js
and add satellizer
as an app dependency as follows:
angular.module('starter', ['ionic', 'satellizer', 'starter.controllers'])
Login Page
We will use ionic's default login page available to us from the starter pack. So open the login.html
file located in templates folder.
<ion-modal-view>
<ion-header-bar>
<h1 class="title">Login</h1>
<div class="buttons">
<button class="button button-clear" ng-click="closeLogin()">Close</button>
</div>
</ion-header-bar>
<ion-content>
<form>
<div class="list">
<label class="item">
<button class="button button-block button-positive" ng-click="authenticate('facebook')">Facebook Auth</button>
</label>
</div>
</form>
</ion-content>
</ion-modal-view>
We removed the username/password fields and removed the form submit handler. Instead we attached the Facebook Auth
button an ng-click attribute that will call in turn to our login controller.
UserService
Next we will create a centralised UserService that will perform the authentication and manage login state.
Create a new file inside js folder and name it user.service.js
(function(){
"use strict";
angular
.module('starter')
.factory('UserService', UserService);
function UserService($rootScope, $auth) {
var userData = $auth.getPayload();
return {
isAuthenticated: function(){
return $auth.isAuthenticated();
},
authenticate: function(provider) {
$auth
.authenticate(provider)
.then(this.successAuth)
.catch(this.failedAuth);
},
logOut: function() {
$auth.logout();
userData = undefined;
$rootScope.$emit('userLoggedOut');
},
getUser: function(){
return userData;
},
successAuth: function() {
userData = $auth.getPayload();
$rootScope.$emit('userLoggedIn', {data: userData});
},
failedAuth: function() {
userData = undefined;
$rootScope.$emit('userFailedLogin');
}
}
}
})();
This service will hold the user data retrieved from the server and will perform the authentication process. Add user.service.js
to your index.html
file:
<script src="js/app.js"></script>
<script src="js/user.service.js"></script>
<script src="js/controllers.js"></script>
After creating our service we can inject it to our controller AppCtrl
located inside controllers.js file.
We will then create a new method to match the ng-click
we provided our view earlier:
$scope.authenticate = function(provider) {
UserService.authenticate(provider);
}
Then we will use an event handler for an event fired from UserService to be informed for when the user is logged or not.
The entire AppCtrl
will look like this:
.controller('AppCtrl', function($rootScope, $scope, $ionicModal, UserService) {
// Create the login modal that we will use later
$ionicModal.fromTemplateUrl('templates/login.html', {
scope: $scope
}).then(function(modal) {
$scope.modal = modal;
});
// Triggered in the login modal to close it
$scope.closeLogin = function() {
$scope.modal.hide();
};
// Open the login modal
$scope.login = function() {
$scope.modal.show();
};
$scope.authenticate = function(provider) {
UserService.authenticate(provider);
};
$rootScope.$on('userLoggedIn', function(data){
// here we will recieve the logged in user
console.log(data);
$scope.closeLogin();
});
// will fire in case authentication failed
$rootScope.$on('userFailedLogin', function(){
});
})
And lastly we will need to configure satellizer provider inside app.js
file. Add $authProvider
as the config dependency so our config will look like:
.config(function($stateProvider, $urlRouterProvider, $authProvider) {
var commonConfig = {
popupOptions: {
location: 'no',
toolbar: 'yes',
width: window.screen.width,
height: window.screen.height
}
};
if (ionic.Platform.isIOS() || ionic.Platform.isAndroid()) {
commonConfig.redirectUri = 'http://localhost:8100/';
}
$authProvider.facebook(angular.extend({}, commonConfig, {
clientId: 'your client id from facebook console',
url: 'http://localhost:3000/auth/facebook'
}));
})
Here we are specifying the redirect popup settings, adding our redirectUri (as configured in facebook console, it must match the server port and address running ionic).
Finally we are extending our commonConfig
with facebook clientId and the url of our server endpoint that will catch the Authorization code passed to it automatically by satellizer.
run ionic serve
and navigate to the login modal from the left menu, when clicking on the auth with facebook button you will be redirected to the facebook prompt page, add your credentials(The user with login in must be authorized inside the facebook app settings).
You will then be redirect back to the app and the userLoggedIn
event will fire, you can have the user information extracted within the controller easily with:
$rootScope.$on('userLoggedIn', function(){
$scope.userData = UserService.getUser();
});
You then can assign the data to your scope, or use it inside your UI. Satellizer will automatically send the JWT token assigned to the "authorization" Header on every request made to the server.
You can follow the getting started tutorial from ionic and build the app to your ios\android platform for testing. When you do so, remember to change the url in satellizer's configuration to match your server address.