An Introduction to Persona

By  on  
Mozilla Persona

So you've heard of this new hipster login service called Persona. It promises to relieve you of dealing with passwords, and be easy to setup. Can it really? I'm here to walk you through setting up Persona on your own website, in just a few minutes. At a glance, here's what you'll need to do:

  1. Grab the include.js shim
  2. Hook up your login button to use navigator.id
  3. Verify the credentials navigator.id gives you on your server

So let's dive in, step by step.

include.js

Until Persona is native in all browsers, you'll need to include a shim that provides the navigator.id API in all browsers. While Persona is in beta, we recommend linking directly against our server. Once we feel confident that the internals are exactly the way we want, we can encourage people to self-host. So, throw this at the bottom of your <body>:

  <script type="text/javascript" src="https://login.persona.org/include.js"></script>

Using navigator.id

A Button

If you don't already have a login button, then add one in your markup. We provide some buttons that already look quite swell.

navigator.id.request

I'm going to assume you use jQuery, because most do. If you use something else, then you should know what parts to change.

$("#login-btn").click(function(e) {
    e.preventDefault();
    navigator.id.request();
});

navigator.id.logout

When a user is logged in, you can show a logout button instead, and hook it up like this:

$("#logout-btn").click(function(e) {
    e.preventDefault();
    navigator.id.logout();
});

navigator.id.watch

Next, we can start watching for changes in the declared identity. With this method in place, if a new user has closed your site while confirming their email address, we can still forward them back to your site, and you will receive an onlogin event. There's a few other good reasons, but that's likely the most common.

We do this with navigator.id.watch(). It takes an onlogin method, onlogout method, and a loggedInUser string. If you think the user is logged in, you should pass the email string, and we'll double check it.

navigator.id.watch({
    onlogin: function(assertion) {
         verifyAssertion(assertion);
    },
    onlogout: function() {
   
    },
    loggedInUser: undefined
});

The onlogin callback will be called with an assertion. This is a signed blob with data inside essentially saying "I promise this is foo@bar.com". Still, you can't fully trust the client. So, you need to send this assertion to your server, and verify that it wasn't tampered with, and that the promise isn't a lie. After successfully verifying, you can do your normal session stuff that you would normally do, and then be sure in all subsequent page loads to set loggedInUser to the user's email.

Verification

The verifyAssertion function shown in the onlogin callback above is a function you implement. Again, assuming jQuery, it could look something like this:

function verifyAssertion(assertion) {
    $.post("/auth/verify", { assertion: assertion }, function onSuccess(resp) {
         // maybe you return a json response including the email
         updateUser(resp.email);
    });
};

As with the shim, we currently recommend you ask our verification server to verify the assertion for you, but once we're certain theres no bugs in the verification process, you'll be welcome to self-host a verification method on your own server.

Our verifier service will return a valid JSON response if the assertion is valid:

{
    "status": "okay",
    "email": "foo@bar.com",
    "audience": "https://yoursitehere.com",
    "expires": 1308859352261,
    "issuer": "bar.com"
}

Here's an example using Python and the Requests library:

data = {'assertion': assertion, 'audience': 'https://yoursitehere.com'}
resp = requests.post('https://verifier.login.persona.org/verify', data=data, verify=True)
json = resp.json()
if json['status'] == 'okay':
    # use json['email'] to do your normal logging in
    # i made up a login mechanism here
    email = json['email']
    user = User.objects.get(email=email)
    if not user:
        user = User.objects.create(email=email)
        session.userid 
    session.userid = user.pk
    return { 'email': email }

If the assertion is valid, we logged the user in if we've seen them before, or create a new user if we haven't. You can imagine what you would do if resp.json['status'] was not okay.

That's it!

You've now got Sign Up and Sign In implemented. You don't need to worry yourself with hashing passwords, showing captchas, or any like matter. If you liked all that, here's some additional resources to learn more and get the most out of Persona:

Sean McArthur

About Sean McArthur

I’m a 25 year-old web developer in Orange County, California, trying to make logins on the Internet better.

Recent Features

  • By
    7 Essential JavaScript Functions

    I remember the early days of JavaScript where you needed a simple function for just about everything because the browser vendors implemented features differently, and not just edge features, basic features, like addEventListener and attachEvent.  Times have changed but there are still a few functions each developer should...

  • By
    Vibration API

    Many of the new APIs provided to us by browser vendors are more targeted toward the mobile user than the desktop user.  One of those simple APIs the Vibration API.  The Vibration API allows developers to direct the device, using JavaScript, to vibrate in...

Incredible Demos

  • By
    JavaScript Canvas Image Conversion

    At last week's Mozilla WebDev Offsite, we all spent half of the last day hacking on our future Mozilla Marketplace app. One mobile app that recently got a lot of attention was Instagram, which sold to Facebook for the bat shit crazy price of one...

  • By
    HTML5 download Attribute

    I tend to get caught up on the JavaScript side of the HTML5 revolution, and can you blame me?  HTML5 gives us awesome "big" stuff like WebSockets, Web Workers, History, Storage and little helpers like the Element classList collection.  There are, however, smaller features in...

Discussion

  1. If I recall correctly in requests>=1.0 json is method, not property.

    • Ack, you’re right. I forgot the parens in the example.

  2. Please, post us a tutorial to use Persona in native apps of Android & iOS using WebView

  3. Thanks for the introduction of Persona and the instruction of installing!

  4. I’ve been waiting for this to get a release, but one thing I don’t understand is how it’s different to, say, openID, or OAuth? Is this not just another competing standard? http://xkcd.com/927/

  5. It seems as though you don’t collect any information other than the email address. Does this mean it is safe for schools to use Persona? I am thinking about the COPPA requirements.

  6. So you just check the ID of the browser software… thats not secure at all, no use ion shared computers, only good for mobile

  7. Interesting to see that they focus on privacy compared to openID. Will give it a try this weekend.

  8. Finally a good explanation of Persona, so even I can implement it :-)

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!