Decoding an Auth0 JSON Web Token with C#

In my previous post, I created a page that submits the JSON Web Token I received back from authenticating against Auth0 to a controller on the ASP.NET WebAPI side of my application. However, I have not authenticated that connection yet. How does one decode an Auth0 JSON Web Token?

It turns out there are some great libraries out there that do just this. But you have to know how to use them and Auth0 doesn’t just come out and say it unfortunately. So I had to do a bit of investigation.

What I want out of today is to alter the response to the SpellsController. Right now, it returns {id:1}. If the user is not authenticated, I still want that returned right now – I’m only going to validate the JSON Web Token. If the user presents a JSON Web Token (as part of the Authorization header) then I want to decode it and return the decoded version instead.

Configuring the Auth0 Settings

I’m dealing with client secrets here, so it’s important that I do this properly. I’ve created a config-local.json file with the following contents:

{
  "Auth0": {
    "ClientID": "{{CLIENTID}}",
    "ClientSecret": "{{CLIENTSECRET}}",
    "Domain": "{{DOMAIN}}.auth0.com"
  }
}

Replace your Auth0 settings in this file. My file is not checked in – in fact it’s explicitly ignored by my .gitignore file so you will have to create this file. My Startup.cs class does not read this file yet, so I need to do an adjustment to the constructor to do that:

        public Startup()
        {
            Configuration = new Configuration()
                .AddJsonFile("config.json", optional: true)
                .AddJsonFile("config-local.json", optional: true)
                .AddEnvironmentVariables();
        }

I also want to ensure that these values are made available via dependency injection. I’ve created a directory called Settings and added an Auth0Settings.cs class:

namespace aurelia_2.Settings
{
    public class Auth0Settings
    {
        public string ClientId { get; set; }
        public string ClientSecret { get; set; }
        public string Domain { get; set; }
    }
}

To create this object and fill it in, I’m going to edit the ConfigureServices() method in Startup.cs:

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<Auth0Settings>(Configuration.GetSubKey("Auth0"));
            services.AddMvc();
        }

Any controller that needs access to this information can now get it via dependency injection. That includes my SpellsController.cs:

using aurelia_2.Settings;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.OptionsModel;

namespace aurelia_2.Controllers
{
    [Route("api/[controller]")]
    public class SpellsController : Controller
    {
        private readonly IOptions<Auth0Settings> auth_settings;

        public SpellsController(IOptions<Auth0Settings> settings)
        {
            this.auth_settings = settings;
        }

Now that my controller has the settings, how do I actually retrieve and decode the Json Web Token? Getting the Json Web Token is trivial – the HttpContext is passed into the controller by virtue of being a Controller:

        [Route("")]
        public string GetAll()
        {
            if (this.Context.Request.Headers.ContainsKey("Authorization"))
            {
                var authHeader = this.Context.Request.Headers["Authorization"];
                var authBits = authHeader.Split(' ');
                if (authBits.Length != 2)
                {
                    return "{error:\"auth bits needs to be length 2\"}";
                }
                if (!authBits[0].ToLowerInvariant().Equals("bearer"))
                {
                    return "{error:\"authBits[0] must be bearer\"}";
                }
                return string.Format("{success:\"{0}\"", authBits[1]);
            }
            return "{id:1}";
        }

Decoding it turned out to be a challenge. First off, the client secret (which is used in the decoding) is not base-64. We need to do two replacement on it – the underscore needs to be turned into a slash and the minus needs to be turned into a plus. I then need to base-64 decode the resulting string:

var b64secret = auth_settings.Options.ClientSecret
                   .Replace('_', '/').Replace('-', '+');
var secret = System.Convert.FromBase64String(b64secret);

I’m going to use a simple JWT library I found on NuGet for the actual decoding. You could roll your own but there really isn’t a reason to do so. Just include JWT in your project.json file and you can then use it. To decode the Json Web Token:

string claims = JWT.JsonWebToken.Decode(authBits[1], secret);
return claims;

Putting it all together, here is my SpellsController now:

using aurelia_2.Settings;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.OptionsModel;

namespace aurelia_2.Controllers
{
    [Route("api/[controller]")]
    public class SpellsController : Controller
    {
        private readonly IOptions<Auth0Settings> auth_settings;

        public SpellsController(IOptions<Auth0Settings> settings)
        {
            this.auth_settings = settings;
        }

        [Route("")]
        public string GetAll()
        {
            if (this.Context.Request.Headers.ContainsKey("Authorization"))
            {
                var authHeader = this.Context.Request.Headers["Authorization"];
                var authBits = authHeader.Split(' ');
                if (authBits.Length != 2)
                {
                    return "{error:\"auth bits needs to be length 2\"}";
                }
                if (!authBits[0].ToLowerInvariant().Equals("bearer"))
                {
                    return "{error:\"authBits[0] must be bearer\"}";
                }
                var b64secret = auth_settings.Options.ClientSecret
                        .Replace('_', '/').Replace('-', '+');
                var secret = System.Convert.FromBase64String(b64secret);
                string claims = JWT.JsonWebToken.Decode(authBits[1], secret);
                return claims;
            }
            return "{id:1}";
        }
    }
}

When you run this project and click on the Spells link, you will get something like the following:

{"iss":"https://{{DOMAIN}}.auth0.com/","sub":"windowslive|d022033c6e98e5cd","aud":"{{CLIENTID}}","exp":1434955982,"iat":1434919982}

The domain and client ID will be replaced by yours of course. There is an expiry time. This is my account as authenticated by my Microsoft account. It’s still not enough to get the actual credentials, but I have enough information to ask for the profile and then associate the information in the profile with the sub-credential.

This is less than ideal. The ideal situation would be to create a piece of middleware that created an Identity from this information. That identity could then be used by the identity sub-system in ASP.NET to “do the right thing” when an [Authorize] decorator was used on the controller. That’s the normal way of determining if a user is authenticated. I’d also want to check the expiry date and the client ID. That, however, is the subject of another blog post.

For now, the code used in this blog post is posted to my GitHub Repository.