In Building Tweets from the Vault: NancyFX tips and tricks we took a look at some of the refactoring-friendly approaches we can take when building a NancyFX application.

In this post we’ll see a very simple example of how Tweets from the Vault uses Twitter and Tweetinvi, a nice-to-call .NET library for Twitter. Tweetinvi has a whole lot more features than authentication but authentication in general is the main focus of this post, so here goes.

I’ll state in advance that this advice only briefly touches upon some really elementary application security. I’ll write a bit more about that in subsequent posts but please don’t treat this advice as anything other than a few brief pointers on the most basic of things. Do your homework. This stuff is important.

Requiring authentication in NancyFX

To begin with, our Nancy application has a base module class from which almost all others derive:

public abstract class AuthenticatedModule : RoutedModule
{
    protected AuthenticatedModule()
    {
        this.RequiresAuthentication();
    }
}

Our AuthenticatedModule just demands authentication and leaves everything else to its derived classes. It’s worth noting that there’s also a convention test (which we’ll discuss in another post) that asserts that every single module in the app must explicitly derive from either AuthenticatedModule or UnauthenticatedModule so as to leave no room for “Oh, I forgot to set the security on that one.”

In Tweets from the Vault, we’re using NancyFX’s StatelessAuthentication hook. We actually add an item to the request pipeline to check for 401 responses and send a redirect. In this way, our individual modules can just demand an authenticated user and return a 401 if not. It’s up to the rest of our pipeline to figure out that we should probably present a kinder response.

In our bootstrapper:

protected override void ApplicationStartup(ILifetimeScope container, IPipelines pipelines)
{
    ConfigureLogging(container);
    using (Log.Logger.BeginTimedOperation("Application starting"))
    {
        // A bunch of irrelevant stuff elided here
        ConfigureAuth(pipelines);
    }
}

private static void ConfigureAuth(IPipelines pipelines)
{
    // Yes, we're using the container as a service locator here. We're resolving
    // a .SingleInstance component once in a bootstrapper so I'm okay with that.
    var authenticator = IoC.Container.Resolve<Authenticator>();

    StatelessAuthentication.Enable(pipelines,
                                   new StatelessAuthenticationConfiguration(authenticator.Authenticate));

    pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
    {
        if (ctx.Response.StatusCode == HttpStatusCode.Unauthorized)
        {
            var response = new RedirectResponse(Route.For<SignIn>());
            ctx.Response = response;
        }
    });
}

Let’s have a look at what this is doing. We can see that the item is being added to the end of the pipeline. That means that it will be executed after our module has done its thing and returned. If the module does an early exit and returns a 401, that will be observable in ctx.Response.StatusCode and we’ll mess with it; otherwise we’ll just pass the response straight through.

If we’ve observed a 401, we clobber the 401 response with a 302 and bounce the user back to the SignIn page using the Route.For expression that we looked at in Building Tweets from the Vault: NancyFX tips and tricks. It’s noteworthy that the browser will never see a 401; just a 302.

What about Twitter and OAuth?

The assumption I’m making here is that you’ll actually want to do something on behalf of a user using the Twitter API. That’s pretty obvious as it’s what Tweets from the Vault does, but I’m going to state up-front: if all you want is an identity via OAuth, this is a harder way to do it than you need. If you want API access, however, then read on.

The first thing you’ll need is an application on Twitter. Go to apps.twitter.com to create one.

The next thing you’ll need is an x.509 certificate. You’ll be telling Twitter to pass keys to access other people’s accounts via GET parameters, so don’t be sending those around the place in plaintext. Incidentally, Twitter does support localhost as a valid redirect URL target, so you’ll be fine for your own testing. Just make sure that you never present a sign-in/sign-up page other than via HTTPS, and likewise make sure your callback URL is HTTPS as well.

You’ll also want the Tweetinvi package:

Install-Package Tweetinvi

Once we’ve hit our SignIn page, it creates a Twitter sign-in credentials bundle using Tweetinvi. This isn’t exactly the code in Tweets from the Vault as there are a few abstractions here and there - I’ve inlined a few things - but it’s pretty close. In our SignIn module:

// You'll want to stash these somehow as there's a single-use token in there
// that you'll need to decode the response.
var temporaryCredentials = TwitterCredentials.CreateCredentials(userAccessToken,
                                                                userAccessSecret,
                                                                _twitterConsumerKey,
                                                                _twitterConsumerSecret);
var authenticationUrl = CredentialsCreator.GetAuthorizationURLForCallback(temporaryCredentials, redirectUrl);

// Hack because the Tweetinvi library doesn't seem to support just authentication - it wants to make an
// authorize call all the time. This will happen anyway on the first time someone uses your app but
// forever after an authenticate call will just bounce straight back whereas an authorize call will
// continue to prompt.
authenticationUrl = authenticationUrl.Replace("oauth/authorize", "oauth/authenticate");

We redirect the user to that authenticationUrl, which will be somewhere on twitter.com, and Twitter will present them with an “Authorize this App” page.

Then, in our SignInCallback module:

var temporaryCredentials = /* fetch these from wherever you stashed them */
var userCredentials = CredentialsCreator.GetCredentialsFromCallbackURL(callbackUrl, temporaryCredentials);
var twitterUser = User.GetLoggedUser(userCredentials);

At this point, we have a valid Twitter user who’s been verified for us by Twitter (thank you :) ) We’ll also have a set of keys to allow us to make API calls as that user to the extent permitted by the privileges that your app was granted by the user.

Of course, if the user declines to authorise the Twitter app to use their account then you’ll get back a different response. Be sure to handle that.

Now what?

Now we have a user who’s just presented us with a valid set of callback tokens from Twitter via a redirect URL. That’s nice, but we shouldn’t be leaving those lying around. What we should be doing is generating our own authentication token of some sort and sending that back as a cookie. (Remember to give people some way to destroy that cookie once they leave a machine, too - you need a “Sign out” button[1]!)

A good way to do this is using a JSON Web Token or similar. There are a bunch of libraries (and opinions) out there on The One True Way™ to do it but the general principle is roughly the same as HTTP cookies: you shove a bunch of claims into a JSON object, sign it and give it to the browser. When it makes a request it can supply that via a cookie.

The JWT standard doesn’t specify encryption - it’s about sending information in plaintext but making it verifiable. That said, if you don’t have to inter-operate with anyone else (i.e. you’re just doing your own sign-on, not implementing SSO across a group of sites) then go ahead and encrypt it. It will help prevent other people stickybeaking into what you’ve bundled into there but still let you use someone else’s library code rather than hand-rolling your own. It should go without saying[2] that if you’re going to put any sensitive information into it then 1) have a careful think about whether you actually need to do that, and 2) make sure you’re using a reputable encryption algorithm with a decent-length key.

Using this approach you can put pretty much anything into your token. As a general rule, I’d like to be able to load a page and only hit persistent storage for data specific to that page. Loading a user’s name, profile picture URL or anything else that is part of the ambient experience goes into the encrypted token. This means that I can render most pages without hitting a dbo.Users or similar. The token doesn’t need to be readable by anyone else but it does need to be relatively small as it’s going to be transmitted by the browser on every request. Also think about what you’ll do in the case of wanting to disable a user account - if you’re not checking dbo.Users every request then how will you know to return a 403?

Be sensible. Don’t create another ViewState. Don’t treat it like session state[3].

So we’re done?

Not quite. You’ll probably want to create your own representation of a user once you have a confirmed Twitter identifier. I’d also use the Twitter 64-bit int as your foreign key, not the username, as that may well change.

It’s worth bearing in mind that Twitter’s OAuth solution does not provide users’ email addresses so that’s something you’ll have to either request for yourself or live without. That’s up to you :) Likewise, we’re relying on Twitter’s anti-spam measures to prevent malicious sign-ups. That’s not unreasonable in the first instance but don’t expect it to be perfect.

In the next post in this series, we’ll take a look at some interesting domain event modelling as part of implementing payments using Stripe.

[1] And it should generate a POST request, not a GET one, but that’s a story for another day.

[2] Hence, of course, needing to say it…

[3] An evil to be discussed some other time…