Remote Verification API

On November 30th, 2016, Mozilla shut down the persona.org services. Persona.org and related domains will soon be taken offline.

For more information, see this guide to migrating your site away from Persona:

https://wiki.mozilla.org/Identity/Persona_Shutdown_Guidelines_for_Reliers

Summary

When a user tries to log into a website, their browser generates a data structure called an assertion, which is essentially a cryptographically signed email address. The browser sends this assertion to the website, which must verify that the assertion is valid before logging the user in.

Assertions can be verified locally, or with an API hosted at https://verifier.login.persona.org/verify. This page describes how to use the API.

Method

HTTP POST request to https://verifier.login.persona.org/verify.

Parameters

assertion
The assertion supplied by the user. Available as the first parameter passed to the onlogin function in navigator.id.watch().
audience
The protocol, domain name, and port of your site. For example, "https://example.com:443".

Return values

The call returns a JSON structure containing a status element, which may be either "okay" or "failure". Depending on the value of status, the structure contains additional elements listed below.

"okay"

The assertion is valid.

In this case the JSON structure contains the following additional elements:

"email" The address contained in the assertion, for the intended person being logged in.
"audience" The audience value contained in the assertion. Expected to be your own website URL.
"expires" The date the assertion expires, expressed as the primitive value of a Date object: that is, the number of milliseconds since midnight 01 January, 1970 UTC.
"issuer" The hostname of the identity provider that issued the assertion.

"failure"

The assertion is invalid. In this case, the JSON structure contains one additional element:

"reason" A string explaining why verification failed.

Examples

node.js

This example uses a node.js server using express.js

var express = require("express"),
    app = express.createServer(),
    https = require("https"),
    querystring = require("querystring");
/* ... */
// The audience must match what your browser's address bar shows,
// including protocol, hostname, and port
var audience = "http://localhost:8888";
app.post("/authenticate", function(req, res) {
  var vreq = https.request({
    host: "verifier.login.persona.org",
    path: "/verify",
    method: "POST"
  }, function(vres) {
    var body = "";
    vres.on('data', function(chunk) { body+=chunk; } )
        .on('end', function() {
          try {
            var verifierResp = JSON.parse(body);
            var valid = verifierResp && verifierResp.status === "okay";
            var email = valid ? verifierResp.email : null;
            req.session.email = email;
            if (valid) {
              console.log("assertion verified successfully for email:", email);
              res.json(email);
            } else {
              console.log("failed to verify assertion:", verifierResp.reason);
              res.send(verifierResp.reason, 403);
            }
          } catch(e) {
            console.log("non-JSON response from verifier");
            // bogus response from verifier!
            res.send("bogus response from verifier!", 403);
          }
        });
  });
  vreq.setHeader('Content-Type', 'application/x-www-form-urlencoded');
  var data = querystring.stringify({
    assertion: req.body.assertion,
    audience: audience
  });
  vreq.setHeader('Content-Length', data.length);
  vreq.write(data);
  vreq.end();
  console.log("verifying assertion!");
});

via Lloyd Hilaiel

PHP

$url = 'https://verifier.login.persona.org/verify';
$assert = filter_input(
    INPUT_POST,
    'assertion',
    FILTER_UNSAFE_RAW,
    FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH
);
//Use the $_POST superglobal array for PHP < 5.2 and write your own filter 
$params = 'assertion=' . urlencode($assert) . '&audience=' .
           urlencode('http://localhost:8888');
$ch = curl_init();
$options = array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_POST => 2,
    //CURLOPT_SSL_VERIFYPEER => true,   //This currently blocks connection to 'https://verifier.login.persona.org/verify'
    CURLOPT_SSL_VERIFYPEER => 0,
    CURLOPT_SSL_VERIFYHOST => 2,
    CURLOPT_POSTFIELDS => $params
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
echo $result;

Via Christian Heilmann

Java

@Override
protected void doPost(final HttpServletRequest req,
   final HttpServletResponse resp) throws ServletException,
   IOException {
   final String audience = req.getServerName();
   final String assertion = req.getParameter("assertion");
   final Verifier verifier = new Verifier();
   final BrowserIDResponse personaResponse = verifier.verify(assertion,audience);
   final Status status = personaResponse.getStatus();
   if (status == Status.OK) {
     /* Authentication with Persona was successful */
     String email = personaResponse.getEmail();
     log.info("{} has sucessfully signed in", email);
     HttpSession session = req.getSession(true);
     session.setAttribute("email", email);
   } else {
     /* Authentication with Persona failed */
     log.info("Sign in failed...");
   }
}

Via Javier

 

Note: If you send the assertion and audience parameters as a JSON-object, they must not be URL-encoded. If they are sent as regular HTTP POST parameters, as in the example above, they must be URL-encoded.

Document Tags and Contributors

Tags: 
 Last updated by: Sheppy,