For a website I'm building in ASP.NET MVC 5/Web API 2 I wanted to simply support Mozilla Persona as the one and only login system for the site. After finding the right blog posts (which was harder than I expected), particularly Brock Allen's primer, I found OWIN and ASP.NET Identity made it easier than I expected. I'm posting this in the hopes that it might help the next person attempting this.

using Microsoft.AspNet.Identity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web.Http;

namespace MyApp.Controllers
    public class PersonaController : ApiController
        // From:
        public const string PersonaAuthenticationType = DefaultAuthenticationTypes.ApplicationCookie;

        public async Task<IHttpActionResult> Login([FromBody]JObject assertion)
            var http = new HttpClient() { BaseAddress = new Uri(Properties.Settings.Default.PersonaVerificationBaseUrl), };
            var body = await JsonConvert.SerializeObjectAsync(new
                assertion = (string)assertion["assertion"],
                audience = Properties.Settings.Default.PersonaAudienceUrl,
            var result = await http.PostAsync("verify", new StringContent(body, System.Text.Encoding.UTF8, "application/json"));

            dynamic response = JObject.Parse(await result.Content.ReadAsStringAsync());

            var status = (string)response.status;
            if (result.IsSuccessStatusCode && string.Equals(status, "okay", StringComparison.OrdinalIgnoreCase))
                var claims = new Claim[]
                    new Claim(ClaimTypes.Name, (string),
                    new Claim(ClaimTypes.Email, (string),
                    new Claim("persona-expires", (string)response.expires),
                    new Claim("persona-audience", (string)response.audience),
                    new Claim("persona-issuer", (string)response.issuer),
                    new Claim(ClaimTypes.AuthenticationMethod, "Persona"),
                var identity = new ClaimsIdentity(claims, PersonaAuthenticationType);
                var ctx = Request.GetOwinContext();
                result.StatusCode = HttpStatusCode.BadRequest;

            return ResponseMessage(result);

        public IHttpActionResult Logout()
            var ctx = Request.GetOwinContext();
            return Ok();