Example of server-based login with PhoneGap

Yesterday I worked on a simple PhoneGap that would demonstrate how to perform a login before using the application. (Ok, technically, you are using the application when you login, but you get my drift.) I worked up a simple demo of this and then extended it to allow for automatic login after you’ve first successfully authenticated. This could probably be done better, but here’s my first draft demo application that will hopefully be useful to others.

I began by creating a new PhoneGap application in Eclipse and included jQuery Mobile. My home page will include my login form and upon successful login I’ll simply push the user to the “real” home page. Here’s the login screen.


<!DOCTYPE HTML>
<html>

<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Auth Demo</title>
<link rel="stylesheet" href="jquery.mobile/jquery.mobile-1.0rc2.css" type="text/css" charset="utf-8" />
<script type="text/javascript" src="js/jquery-1.7.min.js"></script>
<script type="text/javascript" charset="utf-8" src="js/phonegap-1.2.0.js"></script>
<script src="jquery.mobile/jquery.mobile-1.0rc2.js"></script>
<script type="text/javascript" charset="utf-8" src="js/main.js"></script>
</head>

<body onload="init()">

<div id="loginPage" data-role="page">

<div data-role="header">
<h1>Auth Demo</h1>
</div>

<div data-role="content">

<form id="loginForm">
<div data-role="fieldcontain" class="ui-hide-label">
<label for="username">Username:</label>
<input type="text" name="username" id="username" value="" placeholder="Username" />
</div>

<div data-role="fieldcontain" class="ui-hide-label">
<label for="password">Password:</label>
<input type="password" name="password" id="password" value="" placeholder="Password" />
</div>

<input type="submit" value="Login" id="submitButton">
</form>

</div>

<div data-role="footer">
<h4>© Camden Enterprises</h4>
</div>

</div>

</body>
</html>

I assume most of my readers are familiar with jQuery Mobile now so I won’t discuss the mechanics of it above. That being said, here’s a quick screen shot of how this looks.

Ok, now let’s switch over to the code.

function init() {
document.addEventListener("deviceready", deviceReady, true);
delete init;
}

function deviceReady() {

$("#loginForm").on("submit",function(e) {
//disable the button so we can't resubmit while we wait
$("#submitButton",this).attr("disabled","disabled");
var u = $("#username", this).val();
var p = $("#password", this).val();
if(u != '' && p!= '') {
$.post("http://www.coldfusionjedi.com/demos/2011/nov/10/service.cfc?method=login&returnformat=json", {username:u,password:p}, function(res) {
if(res == true) {
$.mobile.changePage("some.html");
} else {
navigator.notification.alert("Your login failed", function() {});
}
$("#submitButton").removeAttr("disabled");
},"json");
}
return false;
});

}

I begin with a deviceready listenener. Technically I’m not actually using any of the phone features for this demo, but in general I think this is a good way to start up your application specific code. The code we care about is in the submit handler for my form. All we need to do when run is do an Ajax request to the server. Remember: The restriction on non-same-domain Ajax requests does not exist in a PhoneGap app. If my authentication returns true, I then use jQuery Mobile’s changePage feature to shift them over to the page. (Note – my remote service is just returning a boolean. It would probably be more useful to return some data about the user. Their username for example. You get the idea I think.)

So this works – but let’s ramp it up a bit. What I’d like to do is ensure that once you login with the application, you don’t have to do it again. This could be optional, but for now I’ve made it just happen by default. I’m going to modify my code to…

  • Store my username and password in local storage upon successful login
  • When the application starts, check for these values, and if they exist, prepopulate the form and submit it automatically

So, my first change was just to store the values. HTML5 local storage to the rescue…


function handleLogin() {
var form = $("#loginForm");
//disable the button so we can't resubmit while we wait
$("#submitButton",form).attr("disabled","disabled");
var u = $("#username", form).val();
var p = $("#password", form).val();
console.log("click");
if(u != '' && p!= '') {
$.post("http://www.coldfusionjedi.com/demos/2011/nov/10/service.cfc?method=login&returnformat=json", {username:u,password:p}, function(res) {
if(res == true) {
//store
window.localStorage["username"] = u;
window.localStorage["password"] = p;
$.mobile.changePage("some.html");
} else {
navigator.notification.alert("Your login failed", function() {});
}
$("#submitButton").removeAttr("disabled");
},"json");
}
return false;
}

Handling the check on startup was a bit more difficult. I’m still trying to wrap my best way to handle events when working with PhoneGap and jQuery Mobile together. For my case, I wanted to populate the form fields. Therefore it made sense to do this both after the page is loaded and the page is “decorated” by jQuery Mobile. For that I needed the pageinit function. However, it is tricky to get the listener in for this. If I add it to my init function, the one called by body/onload, it’s too late. A bit of Googling seems to suggest the best place is in the DOM itself. Here’s how my home page looks now.

<!DOCTYPE HTML>
<html>

<head>
<meta name="viewport" content="width=320; user-scalable=no" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Auth Demo</title>
<link rel="stylesheet" href="jquery.mobile/jquery.mobile-1.0rc2.css" type="text/css" charset="utf-8" />
<script type="text/javascript" src="js/jquery-1.7.min.js"></script>
<script type="text/javascript" charset="utf-8" src="js/phonegap-1.2.0.js"></script>
<script src="jquery.mobile/jquery.mobile-1.0rc2.js"></script>
<script type="text/javascript" charset="utf-8" src="js/main.js"></script>
</head>

<body onload="init()">

<div id="loginPage" data-role="page">

<div data-role="header">
<h1>Auth Demo</h1>
</div>

<div data-role="content">

<form id="loginForm">
<div data-role="fieldcontain" class="ui-hide-label">
<label for="username">Username:</label>
<input type="text" name="username" id="username" value="" placeholder="Username" />
</div>

<div data-role="fieldcontain" class="ui-hide-label">
<label for="password">Password:</label>
<input type="password" name="password" id="password" value="" placeholder="Password" />
</div>

<input type="submit" value="Login" id="submitButton">
</form>

</div>

<div data-role="footer">
<h4>© Camden Enterprises</h4>
</div>

</div>

<script>
$("#loginPage").live("pageinit", function(e) {
checkPreAuth();
});
</script>

</body>
</html>

And here is my re-engineered main.js file:


function init() {
document.addEventListener("deviceready", deviceReady, true);
delete init;
}

function checkPreAuth() {
var form = $("#loginForm");
if(window.localStorage["username"] != undefined && window.localStorage["password"] != undefined) {
$("#username", form).val(window.localStorage["username"]);
$("#password", form).val(window.localStorage["password"]);
handleLogin();
}
}

function handleLogin() {
var form = $("#loginForm");
//disable the button so we can't resubmit while we wait
$("#submitButton",form).attr("disabled","disabled");
var u = $("#username", form).val();
var p = $("#password", form).val();
console.log("click");
if(u != '' && p!= '') {
$.post("http://www.coldfusionjedi.com/demos/2011/nov/10/service.cfc?method=login&returnformat=json", {username:u,password:p}, function(res) {
if(res == true) {
//store
window.localStorage["username"] = u;
window.localStorage["password"] = p;
$.mobile.changePage("some.html");
} else {
navigator.notification.alert("Your login failed", function() {});
}
$("#submitButton").removeAttr("disabled");
},"json");
} else {
//Thanks Igor!
navigator.notification.alert("You must enter a username and password", function() {});
$("#submitButton").removeAttr("disabled");
}
return false;
}

function deviceReady() {

$("#loginForm").on("submit",handleLogin);

}

The code you care about here is checkPreAuth. It basically looks for the existing values, and if there, sets them up in the form and automatically runs the submission. In my tests, this works well. You would probably want to configure the login failed message to handle a case where an auto-login failed. Another issue – and one I do not have a good feel for – is how secure the local storage data will be on the device. Use with caution!

  • Fernando

    Ray, this is great info! I have a question, do you think it is a good idea to store the user & password values and use them on every call that you do to the server, to extract or post info into the database? I mean, like an alternative to create cookies… Thanks in advance!

    • http://www.raymondcamdencom/ Raymond Camden

      I’d use session cookies instead – most app servers should support this and your Ajax requests will use them automatically.

      • Fernando

        Thanks Ray! Keep up this good work! :)

  • Javed

    HI Raymond. Thanks for this article. Forgive me if this sound stupid. But sending the username and password in the url, will it not expose to security threat.

    • http://www.raymondcamdencom/ Raymond Camden

      I’d use a https url to help prevent it from being sniffed, and it isn’t in the URL, but the form data.

  • ramu

    Hi Richard,
    First of all thanks for your source code, I tried the code as follows but i used cordova.js instead of phonegap.js and i’m trying to check the login in mozilla browser but the php api is not returning any response and when i ran the php api url with parameters it is working fine, please help me to solve this problem.

    • http://www.raymondcamdencom/ Raymond Camden

      localhost means your phone, not your local machine. You need to use the IP address of your computer.

      • Ramu

        Thanks for your reply Raymond, I will check and get you back..

        • Ramu

          Hi Raymond. I tried with the IP address but it is not working, please check the attached screen shot once. Please help me to solve this issue ASAP.

          mapp.post(“http://192.168.0.102/android_api/api.php?method=login&returnformat=json”, {username:u,password:p}, function(res) {

          • http://www.raymondcamdencom/ Raymond Camden

            Oh you are testing in the browser? You said this, “i’m trying to check the login in mozilla browser”, but I missed it. You need to enable CORS in your PHP code. It should be simple, but as I don’t do PHP, I can’t tell you how to do it.

          • Ramu

            Hi Raymond,
            Thanks for your response and tried with that and it is working fine.

          • Ramu

            Hi Raymond,

            Thanks in advance, I want to logout from the app, can you please help me how can i logout from the app and redirect to home page. I tried with different things on click on logout button with jquery like
            window.location=”index.html”;
            navigator.app.loadUrl(‘index.html’);
            window.history.go(-(history.length – 1));
            but these are not working, and i’m checking in browser , once the user clicks the logout button it has to redirect the home page but it is staying on the same page and the logout jQuery code is as follows

            $( “#logoutButton” ).click(function() {
            window.localStorage.removeItem(“username”);
            window.localStorage.clear();
            //window.location=”index.html”;
            //navigator.app.loadUrl(‘index.html’);
            window.history.go(-(history.length – 1));
            //alert(‘cleaned’);
            });

            Please help me to solve this issue ASAP.

          • http://www.raymondcamdencom/ Raymond Camden

            Well, first off, jQuery Mobile provides an API to change views. See: http://api.jquerymobile.com/jQuery.mobile.changePage/

  • http://www.lucin.in Sundara Vel

    Login System using PHP & MySQL http://bit.ly/1GN5aEt
    Build using @Ionicframework @phonegap @apachecordova