Remote Verification API

  • Revision slug: Persona/Remote_Verification_API
  • Revision title: Remote Verification API
  • Revision id: 315533
  • Created:
  • Creator: ethertank
  • Is current revision? No
  • Comment

Revision Content

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 web site, 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 {{ domxref("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, 401);
            }
          } catch(e) {
            console.log("non-JSON response from verifier");
            // bogus response from verifier!
            res.send("bogus response from verifier!", 401);

          }
        });
  });

  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 = $_POST['assert'];
$params = 'assertion='.$assert.'&audience=' .
           urlencode('http://example.com:80');
$ch = curl_init();
$options = array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_POST => 2,
    CURLOPT_POSTFIELDS => $params
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
echo $result;

Via Christian Heilmann

Revision Source

<h2 id="Summary" name="Summary">Summary</h2>
<p>When a user tries to log into a website, their browser generates a data structure called an <em>assertion</em>, which is essentially a cryptographically signed email address. The browser sends this assertion to the web site, which must verify that the assertion is valid before logging the user in.</p>
<p>Assertions can be verified locally, or with an API hosted at <span class="link-https"><code>https://verifier.login.persona.org/verify</code></span>. This page describes how to use the API.</p>


<h2 id="Methods" name="Methods">Method</h2>
<p>HTTP POST request to <code>https://verifier.login.persona.org/verify</code>.</p>


<h3 id="Parameters" name="Parameters">Parameters</h3>
<dl>
<dt><code>assertion</code></dt>
<dd>The assertion supplied by the user. Available as the first parameter passed to the <code>onlogin</code> function in {{ domxref("navigator.id.watch()") }}.</dd>
<dt><code>audience</code></dt>
<dd>The protocol, domain name, and port of your site. For example, "<code>https://example.com:443</code>".</dd>
</dl>



<h3 id="Return_values" name="Return_values">Return values</h3>

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


<h4 id="okay" name="okay">"okay"</h4>
<p>The assertion is valid.</p>
<p>In this case the JSON structure contains the following additional elements:</p>

<table class="standard-table" style="width: 80%;">
  <tbody>
    <tr>
      <td>&quot;<code>email</code>&quot;</td>
      <td>The address contained in the assertion, for the intended person being logged in.</td>
    </tr>
    <tr>
      <td>&quot;<code>audience</code>&quot;</td>
      <td>The audience value contained in the assertion. Expected to be your own website URL.</td>
    </tr>
    <tr>
      <td>&quot;<code>expires</code>&quot;</td>
      <td>The date the assertion expires, expressed as the <a href="/en/JavaScript/Reference/Global_Objects/Date/valueOf" title="en/JavaScript/Reference/Global_Objects/Date/valueOf">primitive value of a Date object</a>: that is, the number of milliseconds since midnight 01 January, 1970 UTC.</td>
    </tr>
    <tr>
      <td>&quot;<code>issuer</code>&quot;</td>
      <td>The hostname of the identity provider that issued the assertion.</td>
    </tr>
  </tbody>
</table>



<h4 id="failure" name="failure">"failure"</h4>
<p>The assertion is invalid. In this case the JSON structure contains one additional element:</p>

<table class="compact-table">
  <tbody>
    <tr>
      <td><code>"reason"</code></td>
      <td>A string explaining why verification failed.</td>
    </tr>
  </tbody>
</table>


<h2 id="Examples" name="Examples">Examples</h2>


<h3 id="node.js" name="node.js">node.js</h3>

<p>This example uses a node.js server using express.js</p>

<pre class="brush: 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 &amp;&amp; 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, 401);
            }
          } catch(e) {
            console.log("non-JSON response from verifier");
            // bogus response from verifier!
            res.send("bogus response from verifier!", 401);

          }
        });
  });

  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!");
});

</pre>

<p>via <a class="link-https" href="https://github.com/lloyd/myfavoritebeer.org/blob/06255b960e1f9078bc935c1c7af0662f33c88818/server/main.js#L112">Lloyd Hilaiel</a></p>


<h3 id="PHP" name="PHP">PHP</h3>

<pre class="brush: php">
$url = 'https://verifier.login.persona.org/verify';
$assert = $_POST['assert'];
$params = 'assertion='.$assert.'&amp;audience=' .
           urlencode('http://example.com:80');
$ch = curl_init();
$options = array(
    CURLOPT_URL =&gt; $url,
    CURLOPT_RETURNTRANSFER =&gt; TRUE,
    CURLOPT_POST =&gt; 2,
    CURLOPT_POSTFIELDS =&gt; $params
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
echo $result;</pre>

<p>Via <a class="link-https" href="https://github.com/codepo8/BrowserID-login-with-PHP/blob/184fdb74c8a554461c262875859968154d09288e/verify.php">Christian Heilmann</a></p>
Revert to this revision