Anatomy of a Well Designed AJAX Login Experience

AJAX in itself is a very simple technology, especially with the availability of the right tools. You make a request and pass some parameters, get a response and you render appropriately. The only thing is that the entire process is tedious and if you are the kind of person that likes to do their own plumbing, things can take time. I recently started a web 2.0 project and am nearing completion of the login page. If you are at the beginning of the web2.0 learning curve (barely familiar with JSON, REST, and Prototype) you will find this post interesting. Or, if you have ever designed your own login page, you might find some details here quite useful.

Get Equipped

First things first, find the right tools for the job.

You need a cross-browser Javascript framework to overcome the discrepancies in different browsers and simplify your life. You can skip all those AJAX tutorials out there and just take things for granted when you adopt the Prototype framework. It’s small and has a clean cut library. Though, I should add, I felt the absence of a cross-browser attachEvent but this here script filled that void. As with all things open source, there are different camps and I considered joining the JQuery camp, however, Prototype has a better roadmap and larger community due to its Ruby on Rails endorsement so I went with that.

Next up is client-side validation to help you conserve server load and precious bandwidth by avoiding trips to the server just to validate the password field is not empty. Andrew Tetlaw’s validation.js is built on top of Prototype so it fits the bill quite well. It’s small and I really love the way it tackles validation using CSS classes. For example, the validate-email class verifies the field has a valid email address (I was also able to define my own custom validators and error messages very easily):

<input type="text" size="30" id="email" class="validate-email" />

And what would an AJAX application be if you didn’t sprinkle a few animations and effects. I simply wanted to fade text in and out (for usability reasons I will mention later). Be warned though, it is easy to get tempted by all the cool effects and I wouldn’t be surprised if all sorts of fancy effects start showing up as these FX libraries trickle down to the lower echelons of web enthusiasts. At first, I went with moo.fx because it’s supposed to be superlightweight. However, I ran into some issues with it in IE and switched to Script.aculo.us. Contrary to my initial beliefs, Script.aculo.us is just as small as moo.fx when compressed and possibly better in other arenas.

Speaking of compression, it’s probably a good idea to use a reliable JavaScript compression tool before going live with the website. I haven’t done this yet and I am certain I’ll run into a few other bugs but I’m also certain someone else has already compressed the popular libraries and shared them out. Since all my libraries have relatively big communities, I should be safe here.

Lastly, to exchange data between the web service and the client side Javascript, there are two camps: JSON or XML. I like JSON (JavaScript Object Notation) because it’s very lean compared to XML and much faster because it doesn’t need any complicated parsing. Instead of using <firstname>aleem</firstname>, JSON simply passes { ‘firstname’:’aleem }. And then, instead of parsing the XML using XPATH or whatever, JSON simple calls the eval() function which treats the string literal as an object. The only reason to go with XML is if you want to exchange that data with other non-AJAX services. Even so, JSON is well-formed so it’s likely you can convert it to XML (there might be tools out there already to accomplish this). Prototype does the client-side parsing and on the server side I chose JSON.NET which takes .NET objects and converts them to JSON for Javascript consumption. It’s open source so I can optimize the library and very easily get rid of functionality I don’t need.

A Simple Form: Username, Password and Submit

It seems deceptively simple but if you want it done right, there’s quite a bit of plumbing to do. Let’s begin with the client-side plumbing. Using my validation tools I ran the following client-side validation:

  • Username: should be non-empty, minimum of 5 characters, maximum of 15, alphanumeric and must start with an alphabet. The regex looks like this: ^[a-zA-Z][a-zA-Z0-9]{4,14}$
  • Password: should be non-empty

Further, every time the user hits the submit button, the error messages fades back in. The reason for doing this is because the user will not know the form has been resubmitted using AJAX so the fade-in provides a visual cue that a new action was performed.

The same validation needs to be repeated on the server side. This redundancy is necessary for obvious security reasons–anyone can bypass the form and submit directly to the server. Assuming the validation goes well, the server can respond in any of the following ways:

  • Username does not exist. Display the error on the client side in red and set the focus() to the Login field for convenience.
  • Password does not match. Display the error in red, set the focus() to the Password field and select() the password field text. The reason for selecting the password field is so that the user can start re-typing the password right away. This is not necessary for the Login field however, as it is not asterix’d like the password field and can be corrected visually. Also, select() is better than resetting the field since it gives the user the option to deselect and do the correction.

I did run into Javascript quirkiness here. The order in which the event handlers are executed is convoluted and seemingly non-deterministic in IE. I took me time figuring this out and discovering this is a known issue. Remedying it was simple though–I stuck with only one event handler when order of execution was important. This problem came up during form validation–attaching client side validation and server side validation to the form and having them run in order so if the first failed, the latter would not be executed.

The Server Side

On the server side I am using ASP.NET and wrote HTTP handlers using ASHX files. I also turned off AutoEventWireup which is excessive and unnecessary–it automatically wires up event handling functions to the page. The AJAX framework passes requests over HTTP using GET and POST in general. This is the REST approach and if the Wikipedia explanation seems confusing, just ignore it and grasp the following HTTP request:

POST /ods/serviceall.ashx HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 30

r=login&username=FOO&password=BAR

That’s the request that gets sent out when the AJAX framework makes the call to the server. The thing to note is the last line which contains key/value pairs with three keys: r, username, password. When the server gets this, it parses this and makes a call to login(“FOO”, “BAR”) and sends an HTTP Response back:

HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Tue, 14 Nov 2006 03:19:38 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=cefnyt45pspxr1uiy34lyrj4; path=/; HttpOnly
Set-Cookie: .ASPXAUTH=C3134DF74BDCD48131A084AFFA794C970C0F9998A244B8A707844EF5A8260C40E2164A4B98FD7AE2B6D52D40DD05391B19BEFC8F9D5BA4C627CF4D3C0864F42C6703C7525AA4A3F80DBB2A4774D43388; expires=Tue, 14-Nov-2006 03:49:38 GMT; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 4

true

Ignore the X-Powered-By and other obviously useless headers (I intend to drop them from the server response). When the client-side AJAX framework gets that response it first looks to see if the content contains “true” (last line). If it does then authentication succeeded. For the sake of standardization I will switch to JSON and respond with something like { ‘result’: true } and then simply use: if(result){…} in my Javascript code. However, I use Enumeration types on the server and JSON.NET does not support serializing Enums to JSON, so there’s some work for me here. Anyway, so I grab grab the entire Set-Cookie header and pass it to document.cookie to set the authentication cookie on the client. This cookie is used to verify that the user is authenticated and the login process is now complete.

End of the Beginning

Understanding the guts of the system is not critical to getting the job done but if you want to get intimately familiar with Web 2.0 underpinnings you might want to consider using WFetch or the Live HTTP Headers plugin for Firefox which is terribly useful. The Venkman Javascript Debugger is indispensable if you are into any kind of Javascript development.

I have had a recent inclination toward ASP.NET even though PHP has been very good to me. If you are comfortable with ASP.NET and Visual Studio then you certainly want to use it for learning. PHP will not allow you to set breakpoints, inspect the stack or make runtime modifications. If you are using PHP though, be sure to turn on error reporting if you haven’t already.

My login form still needs a “remember me” checkbox and it needs to handle timed out users so after re-login they can be redirected to the page where they timed out. Once the login experience is all squared out, I will move on to designing a quick and simple sign-up experience.

5/29/2007 Update: I wrote Prototype.js does not offer a cross-browser attachEvent, but Event.observe offers just that. For some reason I overlooked it at the time of writing this post.

7 Responses



This article is no longer open for comments