Here are some notes on what was involved in migrating to the Observer API for those who want to do the same on their sites.
Moving away from hidden forms
This was a reasonable solution when the Persona code was only needed on a handful of pages, but the new API recommends loading the code on all pages where users can be logged in. Therefore, instead of copying this hidden form into the base template and including it on every page, I decided to switch to a jQuery.post()-based solution prior to making any other changes.
From .get() to .watch() and .request()
By far the biggest change that the new API requires is the move from navigator.id.get() to navigator.id.watch() and navigator.id.requets(). Instead of asking for an assertion to verify, two callbacks are registered through
watch() and identification is triggered through
request() (which triggers the
In the case of Libravatar, this involved:
- moving the assertion verification code from the
get()callback to the new
- adding a redirection to the existing logout page from the new
- sharing part of the session state (i.e. which user is currently logged in, if any) with Persona through the
One thing to note is that while
loggedInEmail is going to be renamed to
loggedInUser, this change hasn't hit the production version of Persona yet and so I reverted to the old name after noticing that
onlogin was unnecessarily called on every page load (a fairly expensive operation given the need to transmit and verify the assertion server-side).
Simplifying Content Security Policy headers
Note that if your CSP headers still refer to
browserid.org, you must change them to
Letting Persona know about changes in login state
One important change with respect to the old API is that Persona now keeps track of the login state for your site. If Persona finds a discrepancy between its idea of what your state should be and what you are advertising, it will trigger the appropriate callback (
onlogout) and attempt to resolve the conflict.
This is a very important feature since it will enable features like global logout and persistent cross-device logins, but it does mean that you have to notify Persona whenever your login state changes. If you forget to do this, your state will be automatically changed to match what Persona expects to see.
In Libravatar, this means that when users delete their account, we need to kill their session and tell Persona about it (through navigator.id.logout()). Otherwise, Persona will log them in again, which will of course cause a new account to be provisioned.
Working around the internal login state
The most complicated part of this migration to the new API was around our "add email" functionality, which lets users add extra emails to their existing Libravatar account.
With the old
get() API, adding emails was as easy as requesting additional assertions and verifying them. Under the Observer API, requesting an assertion also changes the internal state that Persona keeps for that website. In practice, it means that after adding a new email in Libravatar, we need to update the "logged in" identifier to match the new one. Failure to do this will prompt Persona to invoke the
onlogout callback with a different email, which will cause the email to get added to a new Libravatar account instead.
There are also two corner cases where Libravatar needs to fallback to its manual authentication backend and tell Persona that nobody is logged in:
- when users remove from their account the email address that their Persona session is tied to
- when users unsuccessfully attempt to add an email that's already claimed by another account
In any case, despite these hacks, I got it all working in the end which is why I'm hopeful that we'll find a way to support this use case.
Taking advantage of the new features
The second feature I tried to enable on Libravatar is the new redirectTo
request() option. Unfortunately, I had to revert this change since in our case, going straight to the profile page causes the @login_required Django decorator to run before the
onlogin callback has a chance to set the session cookie.
In any case, redirecting to the login page already worked and so Libravatar probably doesn't need to make use of this Persona feature.
This migration was harder than I was expecting, but I'm confident that it will become easier in the next few weeks as the implementation is polished and documentation refreshed. I'm very excited about the Observer API because of the new security features and native integration it will enable.
If you use Persona on your site, make sure you sign up to the new service announcement list.