Wednesday, May 15, 2013

Your Jabber ID as your Persona identity

(This is NOT an official Mozilla project and does not in any way reflect the views of my employer.)

Mozilla Persona is a way for users to use their e-mail ID as their identity on the web. While cool, it will only really take off when existing services that people use become Identity Providers. XMPP (Jabber) is a widely deployed IM protocol whose IDs look like e-mail and it is a secure, federated system in alignment with Persona’s goals. I thought it would be really cool if I could log in to Persona enabled sites using Jabber IDs. I’d like to announce browserid-xmpp which does just that.

It should work with any XMPP server that supports components and BOSH. That said I have only tested it on my VPS (with Prosody, ejabberd and Openfire), so any issues and pull requests are welcome, as is a quick comment if you deploy it on your server. You’ll also need a relatively sophisticated web server like Apache or nginx to serve the browserid file with the right Content-Type. CheckMyIdP is a great way to check if everything is setup properly.

browserid-xmpp is two things. The first is a XMPP component that can plug into any XMPP server and answer a certificate signing query. This is a fork of the “official” browserid-certifier with an Jabber-RPC front-end rather than a web service.

The second is the set of provisioning and sign in pages that can be re-used by any domain. The authentication is handled as a two stage process using BOSH. This was my first experience with BOSH and it is ridiculously cool how it works and supports session hand-off to another page, without which this would not be possible. On the sign in page, an XMPP stream is established and authentication is done using standard XMPP authentication. The established BOSH stream has a session ID and every message sent has an incrementing request ID. On successful sign in, the sign in page sticks these two, along with the JID into sessionStorage. The provisioning page reads these out and ‘attaches’ to the existing BOSH stream. Due to the unpredictable nature of the SID and RID, there is a reasonable guarantee that someone who attached to the stream successfully knew about the stream before. The provisioning page then makes a Jabber-RPC call over the same stream to the XMPP component. This call is performed on behalf of the JID and a certificate is sent back to the browser. You are now signed in!

P.S. I’d like to thank Cory Benfield for an excellent guide to writing an IdP.

P.P.S. This post was published right before a 12-hour plane ride, so I’ll be back for tech support in a while.

Friday, April 26, 2013

Push notifications for the Open Web

I’m excited to announce a new WebAPI that Mozilla has been working on for the past few months – Push Notifications for Web applications. Push Notifications let web applications be notified that something has changed on the server and that the application should refresh its data. For example, a calendar application can use Push Notifications such that whenever a new event is added on the server, the calendar application gets started in the background. The calendar app would then add the event to its local agenda and shut down, all without the user’s intervention. When the (pleasantly surprised) user looks at his phone, it has a current copy of his agenda.
Thanks to Push Notifications, Web applications are freed from repeatedly polling for updates, leading to a better experience for everybody. Users get better battery life and more responsive applications. Developers don’t have to re-implement polling logic in every application they write. Mobile devices benefit from intelligent scheduling of notifications to reduce network usage and further improve battery life.
There were several challenges involved in making a push notification system for the open Web:
  1. Developers shouldn’t have to pre-register their applications with a push notification provider. Native app ecosystems require this; for example, you have to get a token from Google to use Cloud Messaging for Android. But for Web apps, which can be self-hosted instead of being distributed by an app store, such restrictions would only limit the audience. In addition, anybody should be free to run their own push server for their devices. Mozilla can run a server for Firefox users. Carriers can run their own servers, on which they can use cellular infrastructure to wake up Firefox OS devices. In fact, an individual user can even run their own push server if they choose.
  2. Users shouldn’t have to log in to a third party to use push capabilities. Note: Users may still need to log in to the app so the app knows what information to push to the device. For example an email app isn’t very useful without logging in.
  3. Protect the user’s privacy. This means that the push server should not receive any private or user-identifying information that is specific to the application. In keeping with this, the push server does not receive any application-specific data. It can only act as a “shoulder tap” or carry a number specifying a “version” or similar identifier.
  4. Make Push Notifications an application wakeup API and not a “user notification” API. The act of displaying a badge or popup notification is not covered by Push Notifications. This decoupling means that applications can use push for all types of tasks, from dealing with IM updates to syncing information across devices without interrupting the user. Applications that do need to notify the user can do so by using the Notifications API with Push.
We believe we now have a system that can satisfy the goals while still being secure and scalable.

How do I make my Web application push enabled?

It is very simple for web applications to use Push Notifications. In fact, in only about 100 lines of code, I modified Gaia to support “Push To Install”. Once you’ve logged in using Persona on your phone, you can install an application to your phone from any browser on any device, just by pushing it to the phone.
The basic flow for Web application developers is:
  1. Your application calls navigator.push.register() to acquire a unique URL, called a push endpoint. This endpoint usually refers to a push server. Your app can call register() multiple times for different uses. For example, an email application could have one push endpoint for every account it tracks.
  2. Your application uses something like XMLHttpRequest to notify your application server of this push endpoint. The application server is maintained by the application developer. For example, if you write a microblogging application, you will have a server where posts are aggregated. You would then associate the push endpoint with the particular user of your application.
  3. When your application server believes something interesting has happened that your application should be notified about, it makes an HTTP PUT request to the push endpoint.
  4. The push server and the user agent (Web browser/Web runtime/Firefox OS device) communicate and deliver a notification to your application. If your application is not running, it will be started in the background and receive the notification. The notification is delivered using System Messages.
  5. When it receives a notification, your application should connect to the application server and download the newest data. Since Push Notifications is a signaling system, it does not carry data in the notification.
I’ll do a blog post with a detailed Push Notifications tutorial soon.


On March 28, 2013 the first pieces of code to enable Push Notifications landed on mozilla-central and are enabled for Firefox OS builds. Set the pref services.push.serverURL to wss:// and the APIs should be available. You can also run your own server.
The protocol is unlikely to change, but client bugs are still being fixed. As such, this is an experimental API. Push Notifications also obsoletes the older Push Notifications API.
Push Notifications is only available to Web applications at this point. There is agreement that web pages loaded in tabs should also be able to use the API, but various technical issues need to be resolved before this can work properly. This is the next major issue the team will address.