Mozilla Persona and OWIN Part 2: Supporting Bearer Tokens

6 months ago

In part one I created a Persona Controller, which provided OWIN Cookie Authentication (as a Web API controller), for supporting MVC logins. Going further down OWIN authentication rabbit hole, I needed to figure out how to get the OWIN bearer token support working, as the new templates default to using that to secure Web API 2 controllers themselves. Turns out this was easier than I expected (most of the previous code copy and pasted over), but felt a lot more complicated in terms of finding useful example documentation. (Not that part one was a cake walk in that department either...)

Here is the ApplicationOAuthProvider class that replaces the bulk of the PersonaController:

using System;
using System.Threading.Tasks;
using Microsoft.Owin.Security.OAuth;
using System.Net.Http;
using System.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Security.Claims;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security;
using System.Collections.Generic;

namespace StingerCheck.Providers
    public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
        private readonly string _publicClientId;

        public ApplicationOAuthProvider(string publicClientId)
            if (publicClientId == null)
                throw new ArgumentNullException("publicClientId");

            _publicClientId = publicClientId;

        public async override Task GrantCustomExtension(OAuthGrantCustomExtensionContext context)
            if (context.GrantType.Equals("persona", StringComparison.OrdinalIgnoreCase))
                var http = new HttpClient() { BaseAddress = new Uri(ConfigurationManager.AppSettings["PersonaVerificationBaseUrl"]), };
                var body = await JsonConvert.SerializeObjectAsync(new
                    assertion = (string)context.Parameters["assertion"],
                    audience = ConfigurationManager.AppSettings["PersonaAudienceUrl"],
                var result = await http.PostAsync("verify", new StringContent(body, System.Text.Encoding.UTF8, "application/json"));

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

                var status = (string)response["status"];
                if (result.IsSuccessStatusCode && string.Equals(status, "okay", StringComparison.OrdinalIgnoreCase))
                    var email = (string)response["email"];
                    var claims = new Claim[]
                        new Claim(ClaimTypes.Name, email),
                        new Claim(ClaimTypes.Email, email),
                        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 oauthIdentity = new ClaimsIdentity ...

Debtstack 2.0

6 months, 1 week ago

I'm calling the latest release of Debstack version 2.0 as it is a fairly big rewrite compared to the original version. (Debtstack binaries; Introductory blog post on Debtstack; Current Debtstack code site) The big deal with this rewrite is it now uses a mostly immutable data model, plus a couple of basic new features.

Immutable Model

I realized that from the beginning I should have built Debtstack on top of a strongly immutable model, and its part of why I chose F# as the language to begin with. (I of course didn't quite follow through on that initially.) It really seems like the right way to go for this project, not least because provides better insight into how the algorithms work and easier debugging and asynchronicity, but more importantly because when dealing with financial data (even just for a read only viewer like Debtstack) it makes sense to try as much as possible never, ever, lose information or even to change things without a log of the change. It hit me early on in this particular rewrite process that essentially the immutable model that I'm using is an interesting (and logical) extreme form of double-entry accounting. I'm pleased at the idea that the code now largely resembles a long-standing accounting best practice.

New Features

Most of the new features exist largely because the new data model facilitates them.

Transaction details
Transactions now have an inspection window showing the complete breakdown of how the chosen algorithm affected them, by double-clicking them in the "Open" list up top or clicking the "Details" button in the grid of Closed items.
"Naive" algorithm
I refer to this as the "But You Don't Have to Take My Word For It" button. This presents the view everyone tends to calculate ...

Persona Controller for OWIN (Web API 2)

7 months, 1 week ago

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();

JoCoCruiseCrazy 4

8 months, 3 weeks ago

In the dark hours of procrastinating the end of an amazing cruise, because it was clear that it would truly be over should my head hit the pillow, I had a sleepy conversation with Jim Boggia. It was exhaustingly late and there had been plenty of alcoholic drinks around that evening to both celebrate and mourn the passing of an amazing week. I am certain that the conversation was nowhere near as lucid as I remember it, but somewhere in there we summarized the cruise near as best we could given the circumstances.

In his set, Jim Boggia played a song titled Listening to NRBQ. In introducing it he asked the various assembled nerds [1], or seamonkeys, how many had heard of the great band NRBQ. There were maybe a dozen of us that had from the hands raised and crowd verbal exclamations. Jim seemed pleased and explained that he normally saw at most three hands to that question in a typical concert.

NRBQ was one of the first concerts I ever attended and was one of the key bands my parents used to teach me a strong love of a good concert. In that late procrastinating conversation Jim Boggia quizzed me a bit on that, including if had seen Steve Ferguson play with them live [2]. As with many such conversations, Jim Boggia let me know that he thought my parents were cool people for loving music and passing that down. Louisville, my hometown, has a unique music history and music scene and NRBQ was a part of that.

The strong, personal connection to NRBQ I think sets the stage for what drunken revelations I had in that culminating evening/morning towards explaining why JoCoCruiseCrazy 4 was one of the most amazing weeks in my life and more interestingly ...

My Friend Niel on the Mathematical Definition of a Picobrewery

9 months, 4 weeks ago

This came up in conversation recently, and then I re-stumbled upon this wisdom in my text messages from May 7, 2012 while searching for an address and feel it is worth preserving. On the subject of using SI prefixes using Anheuser-Busch as the base unit for "1 brewery":

[Anheuser-Busch in St. Louis] brew on the order of 10^9 gallons per year. We brew 10^2 [a nanobrewery]. I was wrong when I referred to our operation as a picobrewery... That would be brewing a shot glass 1/8 full of beer annually.

I keep thinking that a true picobrewery per that definition would be a hilarious, and possibly awesomely hipster, thing to exist.

musdex Inform 7 "Stanza" Handler

1 year, 2 months ago

Not sure yet if this belongs in musdex proper just yet, but this was an interesting toy to build:

# vim: set fileencoding=UTF-8 :
# Inform 7 "Stanza" formatter for musdex
# Take an Inform 7 file (typically and deconstructs it
# into a unique "stanza form" where each major heading starts a new
# text file, newlines are replaced with pilcrows (¶), tabs get added
# newlines, and everything is word-wrapped to 72 characters.
# Why? Interesting source control diffs.
# Copyright 2013 Max Battcher. Some rights reserved.
# Licensed for use under the Ms-RL. See attached LICENSE file.
import datetime
import logging
import os
import os.path
import re
import textwrap
import yaml

HEADINGS = re.compile(r'^(Volume|Book|Part|Chapter|Section)(\s*\d+)?(.*)', re.IGNORECASE)
I7MANIFEST = 'manifest.yaml'
I7EXT = '.txt'
I7FRONTMATTER = 'frontmatter'

_slugify_strip_re = re.compile(r'[^\w\s-]')
_slugify_hyphenate_re = re.compile(r'[-\s]+')
def _slugify(value):
    Normalizes string, converts to lowercase, removes non-alpha characters,
    and converts spaces to hyphens.

    From Django's "django/template/".
    import unicodedata
    if not isinstance(value, unicode):
        value = unicode(value)
    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
    value = unicode(_slugify_strip_re.sub('', value).strip().lower())
    return _slugify_hyphenate_re.sub('-', value).lstrip('-')

class I7StanzaHandler:
    def __init__(self, archive, location, manifest={}):
        self.archive = archive
        self.location = location
        self.manifest = manifest

        if not os.path.exists(self.location):

    def check(self):
        return True

    def extract(self, force=True):
        # No incremental extract, so we ignore force
        manifestfiles = set(self.manifest.keys())
        files = []"Extracting all of %s" % self.archive)
        arc = open(self.archive)
        fname = I7FRONTMATTER + I7EXT
        path = os.path.relpath(os.path.join(self.location, fname))
        out = open(path, 'w')
        if path in manifestfiles: manifestfiles.remove(path)
        yield (path,

        for line in arc:
            m = HEADINGS.match(line)
            if m is not None ...

An Open Letter About Security to My Banks and Insurance Companies

1 year, 2 months ago

Over the next few weeks I plan to send out these personalized pleas for saner security to the banks and insurance companies that I work with. I felt that it was time as customers that maybe some of us more technically literate make a stand and do whatever we can to try to get these companies to pay attention and do the right thing for all of us. Therefore, I figured I'd make this a public letter that others can reuse or recycle. To that end, the letter that follows may be considered for use under the CC0 license.

Dear Bank or Insurance Company,

Given that you and I are both greatly concerned with the security of the accounts that I have entrusted with you, I think it is well past time that we sat down and had a serious conversation about security.

Frankly, I am tired of often answering your "security questions". We should both know by now that this is NOT two-factor authentication and that it is a charade. (

Real two-factor authentication has gotten to the point in the last several months that it should be impossible to continue to ignore the elephant in this room. Real two-factor authentication is now both ridiculously accessible and sufficiently cheap that there should no longer remain any excuses not to support it. At this point every smart phone platform has at least one standards compliant TOTP application. Even truly physical tokens are cheap enough that you could (and should!) give them out like party favors to your customers, as a benefit to both of us. For instance, Amazon Web Services has partnered with Gemalto ( for $13 TOTP tokens and the video game Star Wars: The Old Republic is selling branded ...

Display & Rant: A Podcast of Show and Tell From Opinionated Adults

1 year, 3 months ago

My friend Jordan Wages and I have started a podcast we are calling Display & Rant. Display & Rant Episode 0 has been posted. We're working on our ideas for Episode 1.

Our show notes are on slides, so we are recommending you watch the slide cast version of it (at the top of the page linked above), but for those that prefer more mainstream podcasting tools, you can also subscribe to Display & Rant on iTunes.

Feedback is welcome. I'm looking forward to seeing where this show goes.

Fiasco Poker: Simple Playing Card Variation for Fiasco

1 year, 3 months ago

I've been threatening to write it down for too long now, so I finally wrote down how to play Fiasco with ordinary playing cards instead of dice. I call it Fiasco Poker. I've been meaning to use it alongside a playset, but I still haven't written that yet. I also think it could use playing card-specific Turn and Aftermath tables, but I haven't even started on that either.

Feedback is welcome. I hope it makes for fun sessions for everyone that is willing to try it.


1 year, 4 months ago

As a resident of Downtown Louisville that enjoys interestingly long walks, I walk under a lot of different overpasses and have some time to ponder them while I do so.

The big news here is that in the next few months I-65 through Downtown, and particularly in my home neighborhood between Main and Market Streets, will be expanding from a mere six lanes into a twelve lane monstrosity. [1] This will be nearly half a downtown block wide. It will push what is an already deep cut splitting neighborhoods into a seemingly impassible divide.

I'm sure that it is probably too late to enter into a debate with the current work, as the engineering has already happened and construction has already started in several ways, but I do think a deeper dialog needs to happen on how this expanded overpass will interact with the neighborhood it lives in (and divides).

Based on what I've experienced of which overpasses I feel like hurt the city and which provide interesting flavor instead, I think the big common factor is that Waterfront Park has helped to contextualize its overpasses as brief shady spots in its park. I'd like to hope the same or similar could be accomplished (perhaps not today, but maybe not in the too distant future) with I-65 overpass, at the very least in block between Main and Market, but potentially for a longer swath of its frustrating wall through the heart of Downtown Louisville. I would like to call for, in whatever ways I can manage, some attempt to build a linear park underneath and as a part of the I-65 expansion.

Another example of an overpass that works today is the underside of the George Rogers Clark bridge [2] as it was recently renovated thanks to ...

Skip Generation: Xbox One the Console of Almost

1 year, 5 months ago

Since I've owned video game consoles, every other generation for me has been a skip generation [1]. So it comes again, and it is once again a skip generation and the consoles have a lot to prove to me if they want me to buy one. Given how long the 360 lasted, I'm a bit concerned that this possibly may be effectively my retirement generation from consoles, but there's always the PC. (And maybe it'll only be a half-skip, depending on course corrections, or maybe the Wii U will finally drill directly into the nostalgia center of my heart.)

The Xbox 360 won me over with two key pieces, both expressable as acronyms: XBLA and XNA. Subsequently there were two big things I was waiting to hear about with the Xbox One announcements: backwards compatibility and developer support. Sadly it seems that we get neither, and I am left disappointed with how the Xbox One might have been almost the console for me.

The DRM Issue

Of course, I first have to provide my opinion about the elephant in the room and that is the strange, "new" DRM of the Xbox One. I'm not against the Xbox One DRM on principle. I've been a digital download proponent for some time, and it is very easy to admit that the Xbox One DRM isn't the worst digital download DRM scheme out there. Sure, it's a tiny bit strange that it also applies to physical discs, but I can give that the benefit of the doubt. (Again given that digital download is pretty much my default at this point, and I've never been much of one to trade back games or to buy used ones. Admittedly I've been rather privileged in those ...

Random Access Memories

1 year, 6 months ago

First of all, I think Daft Punk's Random Access Memories is fantastic. Apropos to the album title, my mind starting free associating some praising with faint damnation, [1] and I thought it was funny enough to record here.

Basically, stupid stereotypes in my head believe that the French still think that Jerry Lewis is alive and funny and similarly Disco never died for them. (Look at the band Phoenix, perhaps.) So for Daft Punk this would probably be their most contemporary album to date. It's like how William Gibson slowly merged from the sci-fi vanguard into contemporary literature. Maybe this album is the musical equivalent of Gibson's Thesis, "the future is already here, it is just unevenly distributed... and full of disco."

[1]Which is totally a thing I thought I just made up now, but oh you internet.

On Iron Man 3 (Major Spoilers)

1 year, 6 months ago

Iron Man 3 was a fun comic book film. I find myself in a strange minority, however, in that I feel that it was definitely the weakest of the four Iron Man films to date [1]. I can forgive the fact that Guy Pearce's character is a shallow, two-dimensional hack that seems cloned from the exact same cloth as Jim Carrey's Edward Nigma portrayal. I can forgive the fact that using the acronym AIM, Pearce's Killian didn't actually seem to have one. I can forgive the meandering plot line where it seemed like Killian could never make up his mind whether he was attempting to capture Tony Stark or kill Tony Stark.

What I have a hard time forgiving is how little respect The Mandarin gets in this film. I'm disappointed in how the film wastes foreshadowing and bread crumbs about Ten Rings and The Mandarin from Favreau's films. [2] But before you dismiss this as comic fan complaints, let me point out that I had rather low expectations going in. Like most of my comic knowledge, my knowledge of Iron Man was forged by 90s cartoons (in this case the sometime execrable Iron Man Adventures) and polished with video games, with internet web sites and Wikipedia filling in many of the gaps.

I mostly just want one more scene, or a simple short film, to redeem The Mandarin in the Marvel Cinematic Universe. But I think the real Mandarin would have been a much more interesting foil for Tony Stark in this movie.

Yes, The Mandarin Is Racist

To get it out of the way, I completely realize and agree that The Mandarin [3] is racist in all of his incarnations. One of the things I appreciated about the film was the hints ...

Mini Lecture on LINQ Visualization

1 year, 8 months ago

This topic came up again today when discussing some misapprehensions about what I consider to be some of the basics of how LINQ works. I think there is some use in visualizing the flow of at least three key interfaces through the LINQ operators, with embedded mini-lecture in the notes.

Hopefully people may find this helpful.

On Forgiving Star Wars and The Old Republic's F2P Problems

1 year, 11 months ago

Between Disney buying out Star Wars [1] and letting "free-to-pay" [2] tempt me back to Star Wars: The Old Republic I seem to have forgiven the franchise for some of its worst excesses, bad politics, and general silliness. I won't rehash here the history of how I burnt out on Star Wars in High School, particularly the Expanded Universe, and began to balk at its politics and usage of "sci-fi drag" to retell serialized fairy tales, because I'm sure the internet has indexed plenty of those rants already. Instead, I shall only have to acknowledge that somehow a majority of my anger has melted away into laughter and enjoyment. [3] It has become easier for me to remember that contrary the seriousness of so much of the "Star Wars EU" and its fandom: Star Wars as a franchise always has and really always should be seen as the relative to Indiana Jones as it in fact is; Star Wars is an extension and a piece of the on-going "tradition" of sci-fi serials like Buck Rodgers and Flash Gordon.

So I may have learned to stop worrying and love the bomb, or at least, laugh at it a lot. Laughter, at least, is a good form of amusement. [4]

That out of the way, I wanted to rant a bit about Star Wars: The Old Republic and the crazy way it seems to have implemented F2P which bothers me more than it should. It's not the increasingly standard for all F2P game' over-reliance on random lottery tickets [5], but more a basic confusion at the intended goals of the F2P conversion. For the most part the F2P seems biased towards giving single player content out for free and charging for any multiplayer content whatsoever. This seems somewhat inappropriate ...

Colophon Copyright © 1999-2012 Max Battcher / WorldMaker. Some Rights Reserved.

With our thoughts, we make our worlds. I only buy the best Robots — All my Robots are GSD ServDev® Brand.