Cross-Domain AJAX Requests in Lift

Posted by Matt Farmer on March 03, 2013 · 4 mins read

Today we locked down user authentication on Anchor Tab to be SSL-only (unless I’ve severely screwed something up). As a few of you already know, I’m building Anchor Tab using the Lift Web Framework. I was first introduced to Lift at OpenStudy, and I love it. I actually was recently nominated and made a committer on the project and, although Anchor Tab has prevented me from making any significant code contributions just yet, I’m looking forward to doing so once we get our MVP out the door and we’re in data collection mode for a few weeks.

Now, back to our regularly scheduled programming. Lift makes working with forms over AJAX in a secure manner pretty simple once you get you head around it. Long story short, I had a working Lift ajax form providing us authentication on our landing page. I wanted Authentication to go over HTTPS without requiring the whole site to be HTTPS all the time. This is difficult due to the Same Origin Policy. So, for locking down our user authentication, I had the following options:

  1. Remove the login from the landing and make users go to a separate page. (-10 UX points)
  2. Roll all my own code for the form. (-100 Lift points; -5000 DRY points)
  3. Make the entire site HTTPS-only. (-10^1000 points, because I was stubborn.)
  4. Get the AJAX request that Lift would fire for the authentication to work via iframe or JSONP.

Sure enough, I was able to get the authentication working via JSONP. Turns out that while usually submitting a form will yield a POST request into Lift, GET requests with query strings work just as well. To accomplish this task, I had to replace the default implementation of one of the Lift functions on my landing page, lift_actualAjaxCall, that actually runs the jQuery.ajax function to talk to the server. My replacement looks pretty much like this:

After I had this in place I had working authentication going over HTTPS, completely transparently to the rest of the application. Über-mega-win. One problem though. The jsonp transport for jQuery defines a callback function that you’re supposed to call in whatever JavaScript is sent back down from the server. My code wasn’t doing that, and ended up triggering Lift’s retry mechanisms for failed AJAX requests (presumably because the onSuccess function never got called).

So, the next piece of this riddle was to make the Anchor Tab app intelligent enough to realize when a jQuery response was needed for a response and append it so we don’t get nasty alert dialog boxes saying “The server cannot be contacted at this time.” When I was initially spitballing this idea with Antonio, he first brought up the idea of response transformers. Sure enough, using one of those did the trick.

I added a response transformer (a nice little function that will read the response Lift has generated up to the current point and let you change it) to LiftRules that checks to see if a callback parameter exists for the request. If so, we check to see if the callback is ever mentioned in the response we’re about to send back to the client. If it isn’t, we create a bogus call that triggers the callback and makes everybody happy. Here’s the code for that:

I’m happy to report that so far, things are going well. And by that, I mean it’s working. I’m sure there’s probably something I’ve missed that’ll require bugfixes, so if any of my clever readers see it let me know! ?

Hopefully this will help save some pain for the next person that needs to do this in Lift.

As always, leave me some comment love below. Especially if you have improvements to recommend to the technique. See you on the flip side, readers.