User Authentication in a jQuery Mobile and PhoneGap Application.This article shows you how to implement user authentication in a jQuery Mobile and PhoneGap application. User registration (which we added in the previous chapter of this series) and authentication are the door that users have to go into the application.
The authentication feature has two subsystems that work together. One lives inside the mobile application and captures the user’s credentials, performs a first round of validation, and sends the credentials to the server.
The other subsystem resides on the server. It receives the user credentials sent from the mobile application, authenticates them against profile information stored in a database, and returns a session token back to the app so subsequent requests can be mapped to the correct user in the database.
We created the server side of the authentication feature in the User Registration for a Mobile Application tutorial. In this article we are going to create the mobile app side. Let’s get started.
The Sign In Screen
First, we are going to review the Sign In screen that we designed in a previous article of this series. This is where users will type their email address and password for authentication purposes.
The screen is a jQuery Mobile page that uses the following code:
The page looks like this when the app runs:
Besides the email address and password fields, the page has checkbox that lets the users indicate if they want to keep their session active after they close the application. When users check this box, they will be accepted in without authentication next time they launch the app from the same device.
This feature requires that we define a session expiration setting in the app. The setting will represent the number of days the session will be active.
As you can imagine, we will need to create a similar setting on the server side. We need this so the session token created for users when they sign in remains valid on the server for the same period the session is active on the app. The session expiration should be the same on both the app and the server side for this feature to work correctly.
Adding the Main Menu Page
As a second step, we are going to create the screen where we will take users after they log in successfully. We will name it the Main Menu screen.
The screen is a jQuery Mobile page that will add to the index.html file in the cordova-project/www directory:
Let’s add the following code to the index.html file, immediately after the “page-signin” div’s end tag:
For now we will only place a message in this page indicating that this is the “Main Menu” page. In a future article we will add the main menu elements to the page.
A Note About User Roles
Remember that we planned for the application to also support users with administrative rights. This means that in the future we will need to add user roles logic to the registration and login features. To keep things as simple as possible, we will not touch this area in this particular article.
Now that we have a place to take users after signing in, let’s talk about how we will handle session data.
How to Store Session Data in a PhoneGap Application
The occasionally-connected nature of mobile applications brings along the need to store user information on the application side once you authenticate the user. We will use HTML5 local storage, which is supported by PhoneGap, to persist this information so it’s available each time the user runs the app.
We will use a Class to encapsulate the storage and retrieval of session data in local storage. Let’s add the session.js file to the cordova-project/www/js directory:
In the file, define the Session Class with the following code:
The Session Class is a singleton, which saves us from having instantiate it each time we need to save or retrieve session data. Internally, the Class uses the window.localStorage object to move the data to and from local storage. We call the set method to save data, and the get method to retrieve data.
Confining the session operations to a Class gives us the ability to switch the storage medium – for example, from local storage to file system – without having to modify other modules of the app. What the other modules need to care about is that they can use the Session Class’s set and get methods to save or load session data.
Creating a Controller Class to Perform User Authentication
I mentioned earlier that authenticating a user requires that we perform three steps:
Capture the user’s credentials
Perform a first round of credentials validation (prevent blanks and invalid email addresses)
Send the credentials to the server for authentication.
We will implement these operations inside a controller Class that we will name SignInController. Let’s create the signin-controller.js file in the cordova-project/www/js directory:
In the file, we will first define the SignInController Class with the following code:
The $signInPage variable will hold a reference to the jQuery Mobile page that hosts the Sign In screen. The $btnSubmit, $ctnError, $txtEmailAddress, $txtPassword and $chkKeepSignedIn will hold references to the form elements in the screen and the div element where we will display error messages. The mainMenuPageId variable will hold the id of the jQuery Mobile page that hosts the Main Menu screen.
Input Capture
Next, we are going to create a method where we will acquire the references we declared in the constructor of the Class. Let’s add the init method like so:
In the init method, we use jQuery to acquire the element references that we need. Nothing earth-shattering going on here.
Email Validation
I mentioned that we are going to create a layer of credentials validation inside the app before sending the credentials to the server. One of the pieces of this layer is the validation of the email address entered by the user. Let’s define the emailAddressIsValid method:
his helper method performs a quick regular expression check that returns true if the supplied email address is valid.
Resetting the SignIn Form
We also need a helper method to clear the email address, password and “keep me signed in” form elements when the Sign In screen is activated. Clearing these elements prevents us from accidentally showing any values entered previously.
Let’s create the resetSignInForm method in the Class:
In this method we clear the html in the div that we use to display error messages, and clear the values of the email and password text fields. We also uncheck the “keep me signed in” checkbox, and remove the styles that we use to flag invalid fields.
The invisibleStyle and invalidInputStyle variables hold the names of the CSS classes that we use to hide or flag fields as invalid. We created these classes in a previous chapter of this series, and you can find them in the cordova-project/www/css/app.css file. Here they are so you don’t have to look up the file right now:
Submitting User Credentials to the Server from a PhoneGap Application
The third step of the authentication sequence in our Cordova app is to send the user credentials to the server, and wait for a response that will tell us if we can let the user in.
We will perform this step inside a template method that we will call onSignInCommand. We will invoke this method when the user pushes the Sign In button in the Sign In Screen.
Let’s add the following code to the controller Class:
Inside the method we first reset the styles of any fields that were marked as invalid previously. We do this by hiding the div element where we show error messages, and removing the “invalid input” CSS classes from the email address and password fields:
Next, we check that the user typed some text in the email and password fields. If either field is empty, we show an error message in the “errors” div:
As a third step, we invoke the emailAddressIsValid method created earlier to check that the text entered in the email address field is formatted as an email address:
Finally, we activate the jQuery Mobile load indicator to signal that we are starting a long-running operation, and submit the credentials to the server through an AJAX request.
This is a POST request. We obtain the URL for it from the signInUrl property of the Settings Class. The request’s data property contains the email address and password that we are sending to the server.
Here the interesting stuff happens inside the success function. In it, we hide the jQuery Mobile loading indicator and check the success property of the resp argument, which is sent by the server endpoint:
Creating a Session Object in a Cordova/PhoneGap Application
The resp.success property is true when the authentication succeeds. In such a case, we need to create a session object for the current user:
Notice how we use the Settings.sessionTimeoutInMSec (milliseconds) to create the session expiration date. Also, how we use the Session singleton that we created earlier to save the user profile and session id sent from the server.
We also save the session’s expiration date, and whether the user wants the app to keep her or him signed in the next time they run the app. (Later in this article we will create the code that bypasses the Sign In Screen when a user launches the application.)
After saving the session, we activate the Main Menu screen using jQuery Mobile’s navigate method.
Handling Authentication Failures
The success property returned by the server is false when the authentication fails. In such a case, we need to check the value of the response’s extras.msg property to determine the reason for the failure:
Oops! BookIt had a problem and could not log you on. Please try again in a few minutes.
“); me.$ctnErr.addClass(“bi-ctn-err”).slideDown(); break; case BookIt.ApiMessages.INVALID_PWD: case BookIt.ApiMessages.EMAIL_NOT_FOUND: me.$ctnErr.html(”
You entered a wrong username or password. Please try again.
“); me.$ctnErr.addClass(“bi-ctn-err”).slideDown(); me.$txtEmailAddress.addClass(invalidInputStyle); break; } }
If the server tells us that there was a database error, we alert the user that she or he needs to try again later. We also notify the user when the server tells us that either the email address or password supplied is invalid.
While I am showing you that you can get really detailed with the information that you send from the server, in a production app that’s open to the general public I wouldn’t bubble a database error code all the way to the mobile app. I wouldn’t use separate codes to indicate invalid password and invalid email address either.
Be mindful not to disclose sensitive information when handling response codes from the server. People with bad intentions can use these codes to attack the server endpoint.
Handling Ajax Errors
The remaining code in the Ajax request in the error handler. In it, we just show a generic error to the user:
Including the Session and Controller Classes in the Cordova Project
Let’s go ahead and add references to the session.js and sigin-controller.js files in the cordova-project/www/index.html file. We will add them immediately before the reference to the index.js file:
Instantiating the Controller
Now we can move on to actually using the SignInController Class to perform the authentication. Let’s jump to the index.js file and instantiate the controller. We can do it right after the line that instantiates the SignUpController, which we created in an earlier chapter of this series:
The first action that we will take with the signInController instance is to reset the email address and password fields every time the Sign In screen is activated. We will use jQuery Mobile’s pagecontainerbeforeshow event to detect when the Sign In screen is about to be shown, and reset the fields:
From the code above you will remember that we did the same for the Sign Up screen.
Wiring the Sign In Button to the Controller
We also need to wire the Sign In button on the Sign In sccreen to the controller instance. We will use the page’s beforecreate event to wire a tap handler for the button.
This event triggers before the jQuery Mobile page has been created. We want the tap handler to be already wired when the page is created and shown to the user.
Perfect. Now when a user taps the button, the app will invoke the controllers onSignInCommand method, which will perform the validation of the fields and submit the credentials to the server.
Bypassing the Index Screen Upon Launch if a Session is Still Active
This is a feature that many users will appreciate. The majority of people don’t want to have to type their email address and password every time they launch the application.
If someone went through the Sign In screen and checked off the box indicating that they want to be kept signed in, we saved this selection to local storage. Now we have to add the code to read this flag upon application launch and take the user straight into the app without showing the Index, Sign In or Sign Up screens.
The trick here is to know when the Index page is about to be activated, and both prevent the activation and trigger the navigation to the Main Menu screen, if the “keep me signed in” flag is set. Let’s add the following code to the index.js file:
jQuery Mobile triggers the pagecontainerbeforechange event during the page change cycle prior to any page loading or transition. We can use the event to detect when the user interface is navigating to the Index screen for the first time. We know this is the case when:
The id of the ui.toPage object is the id of the Index screen.
The ui.prePage object is null, meaning that we are coming to the Index screen from another screen.
When we are opening the Index screen for the first time after application launch, we check if there’s an existing non-expired session for which the keepMeSignedIn flag is set. If the session exists, we navigate to the Main Menu screen by replacing the ui.toPage object with the jQuery Mobile page that contains the Main Menu screen.
Summary and Next Steps
In this tutorial we created a user login feature for a Cordova application. The feature has in-application and server-side modules that work together to capture the user’s credentials, validate them and authenticate the user by comparing their email address and a hash of their password against data stored in a database.
In the next chapter of this series we will start implementing the room booking features of the app. Make sure to sign up for my newsletter so you can be among the first to know when my next tutorial is available.