Building Tweets from the Vault: Twitter OAuth

Andrew Harcourt Sun 1 Feb 2015

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...

Building Tweets from the Vault: NancyFX tips and tricks

Andrew Harcourt Mon 19 Jan 2015

In Building Tweets from the Vault: Azure, TeamCity and Octopus, I wrote about the hosting and infrastructure choices I made for Tweets from the Vault. This article will cover a bit more about the framework choices, notably NancyFX.

NancyFX

NancyFX may sound like a bit more of an esoteric choice, especially to the Microsoft-or-die crowd. I've been having a pretty fair amount of success with Nancy, however. I love the way that it just gets out of the road and provides a close-to-the-metal experience for the common case but makes it simple to extend behaviour.

By all means, it's not perfect - I'm not a huge fan of "dynamic, dynamic everywhere" - but it's way better than MVC for my needs. The upgrade path is a whole lot less troublesome, too - the best advice I've found for upgrading between major versions of MVC is to create a new project and copy the old content across.

Application structure

The equivalent of an MVC controller in NancyFX is the module. In a typical MVC controller, there are lots (usually far too many) methods (controller actions) that do different things. While this isn't strictly a feature of the framework, all the sample code tends to guide people down the path of having lots of methods on an average controller, with a correspondingly large number of dependencies.

In MVC, routing to controller actions is taken care of my convention, defaulting to the controller's type name and method name. For instance, the /Home/About path would (by default) map to the About() method on the HomeController class.

Nancy routes are wired up a little bit differently. Each module gets to register the routes that it can handle in its constructors, so if I were to want to emulate the above behaviour I'd do something like this:

public class HomeModule : NancyModule
{
    public HomeModule()
    {
        Get["/Home/Index"] = args => /* some implementation here */;
        Get["/Home/About"] = args => /* some implementation here */;
        Get["/Home/Contact"] = args => /* some implementation here */;
    }
}

Obviously, if we want the same Nancy module to handle more than one route then we just wire up additional routes in the module's constructor and we're good.

This is nice in a way but it's also a very easy way to cut yourself and I tend to not be a fan. Not only that, but it still leads us down the path of violating the Single Responsibility Principle in our module.

My preference is to have one action per module and to name and namespace each module according to its route. Thus my application's filesystem structure would look something like this:

app
    Home
        Index.cs
        About.cs
        Contact.cs

This makes it incredibly easy to navigate around the application and I never have to wonder about which controller/module/HTTP handler is serving a request for a particular path.

My About.cs file would therefore look something like this (for now):

public class About : NancyModule
{
    public About()
    {
        Get["/Home/About"] = args => /* some implementation here */;
    }
}

RoutedModule

One problem with the above approach is that it's not refactoring-friendly. If I were to change the name of the About class then I'd also need to edit the route registration's magic string. Magic strings are bad, mmmkay?

A simple approach for the common case (remembering that it's still easy to manually register additional routes) is to just derive the name of the route from the name and namespace of the module. (Hey, I didn't say that all of MVC was bad.)

public abstract class RoutedModule : NancyModule
{
    protected RoutedModule()
    {
        var route = Route.For(GetType());
        Get[route, true] = (args, ct) => HandleGet(args, ct);
        Post[route, true] = (args, ct) => HandlePost(args, ct);
    }

    protected virtual async Task<dynamic> HandleGet(dynamic args, CancellationToken ct)
    {
        return (dynamic) View[ViewName];
    }

    protected virtual Task<dynamic> HandlePost(dynamic args, CancellationToken ct)
    {
        throw new NotSupportedException();
    }

    protected virtual string ViewName
    {
        get { return this.ViewName(); }
    }
}

This now allows for our About.cs file to look like this:

public class About : RoutedModule
{
}

Routes

We're not quite there yet. I'm not a fan of magic strings and in the above example you can see a call to a static Route.For method. That method is where the useful behaviour is, and it looks like this:

public static class Route
{
    private static readonly string _baseNamespace = typeof (Index).Namespace;

    public static string For<TModule>() where TModule : RoutedModule
    {
        return For(typeof (TModule));
    }

    public static string For(Type moduleType)
    {
        var route = moduleType.FullName
                              .Replace(_baseNamespace, string.Empty)
                              .Replace(".", "/")
                              .Replace("//", "/")
                              .ToLowerInvariant();
        return route;
    }

    public static string ViewName(this RoutedModule module)
    {
        // Left as an exercise for the reader :)
    }
}

This allows us to have a completely refactor-friendly route to an individual action. There are a couple of similar routing efforts for MVC, notably in MVC.Contrib and MvcNavigationHelpers, but this lightweight approach doesn't require building and parsing of expression trees. (It's worth noting that it doesn't account for a full route value dictionary, either, but you can add that if you like.)

In our views, our URLs can now be generated like this:

<a class="navbar-brand" href="@(Route.For<Index>())">
    Tweets from the Vault
</a>

and in our modules, like this:

return new RedirectResponse(Route.For<Index>());

A quick ^R^R (Refactor, Rename, for all you ReSharper Luddites) of any of our modules and you can see that we haven't broken any of our links or redirects.

In the next post in this series, we'll take a quick look at authenticating with Twitter using OAuth.

The boring traveller

Andrew Harcourt Mon 12 Jan 2015

So... it would appear that I've landed in BKK and am in a hotel somewhere.

This one's a short trip (work, not play) and I'm going to be the most boring traveller known to humankind.

Thailand is renowned for its:

  • culture
  • food
  • beaches
  • night life

and while I'm here I'm going to:

  • arrive when it's dark, fly out when it's dark and work in between
  • not try any too-adventurous dishes as my flight back is pretty soon after I arrive and if I'm sick for a nine-hour flight it's not going to be pleasant. And I really need to be functional when I return.
  • not have any daylight hours to go exploring
  • sleep when it's dark.

What I am going to do is take every opportunity to fill up my phone with photos. Watch this space.

About me

My name is Andrew Harcourt.

I'm a software engineer and project rescue specialist. I'm a Principal Consultant at Readify. I also run my own photography company, Ivory Digital.

Work

I'm a solutions architect and software engineer with extensive experience in large-scale, high-load, geographically-distributed systems. I specialise in project rescue, governance and development methodologies.

My main areas of interest are domain-driven design, event sourcing, massively-scalable service architectures and cloud computing.

I'm a regular speaker and presenter at conferences and training events. My mother wrote COBOL on punch cards and I've been coding in one form or another since I was five years old.

Play

Photographer. Ballroom dancer. Cyclist. Motorcyclist. I love my outdoor sports - and anyone who won't dance is chicken.

Subscribe