JWT Tokens

Summary

In this blog post, I’m going to introduce the JWT (pronounced “jot”) token concept.  I’m going to use the code presented in this article (click here) to demonstrate how a token is created and then I’ll discuss the parts of the token and how it is used.

Sample Token

Using the article code, I created a dumb and dirty console app to generate a token with this final code:

var token = new JwtTokenBuilder()
  .AddSecurityKey(JwtSecurityKey.Create("fiver-secret-key"))
  .AddSubject("james bond")
  .AddIssuer("Fiver.Security.Bearer")
  .AddAudience("Fiver.Security.Bearer")
  .AddClaim("MembershipId", "111")
  .AddExpiry(1)
  .Build();

For a real system, you’ll need to store your secret key and you’ll need to make it much larger.  The other variables will differ according to your use of the token.  Before I go into any details on how you would generate and consume the token, I’m going to discuss what the token looks like and how it works.  First, I generated a token from the above code and obtained this result:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqYW1lcyBib25kIiwianRpIjoiNDQ2MDU1MmItNWU5MS00MjcyLWIyMDItMmFlYzFmNWFhNGY3IiwiTWVtYmVyc2hpcElkIjoiMTExIiwiZXhwIjoxNTE5NTkwMjY4LCJpc3MiOiJGaXZlci5TZWN1cml0eS5CZWFyZXIiLCJhdWQiOiJGaXZlci5TZWN1cml0eS5CZWFyZXIifQ.C_Z_fLGhlvbhywwGn727mVSxJM8JlQpw8dZmysTgr1w

If you go to the wiki page on the JWT Token (JSON Web Token), you’ll see a description of the three parts of the token.  If you look closely you can see that there are two dots “.” and they separate the three parts of the token.  Each part is a base 64 encoded string so it is safe to transmit over the web.  The first part is the header.  If you cut the first part you’ll get this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Paste that code into a decoder (click here for an on-line base 64 string decoder), you’ll get this result:

If you dig into the JWT token build method, you’ll see a section where HS256 hashing is used for the signature and this token is a JWT type token.

Take the next block of text (which is long) and copy it (without the dots).  Then put it in the decoder and click on “Decode”.  You should see this:

This is the payload section and you can see all the information that was placed into C# the code earlier.

If you’ve ever used tokens for accessing APIs, you’re probably thinking to yourself: What prevents someone from getting a copy of this token and just changing the information to something else and stealing admin rights or unauthorized data from the API?  That’s where the signature comes in.  The signature is the last part of the token.  The signature represents everything that is in the header and payload, encoded with a secret key and formed into a hash.  The receiver of this token must know the secret key in order to verify the signature.  If anything in the header or payload is altered, the recalculation of the hash will result in a different signature value.

Keep in mind, that the JWT token should not be used to store anything you want to keep secret.  So don’t put your password into the token payload and then expect it to be safe.  Technically, it will be safe from packet sniffers because you should be accessing an API using SSL, but don’t assume that the payload section is encrypted.

If you were to generate another token after the expire time (in my example the expire was set to 1 minute), then the signature will be different.  That’s because the token is time sensitive.  This improves the security, in case the token is intercepted by a third party.  It also prevents a user from reusing the token forever, instead of re-authenticating.  Finally, it prevents a valid token from being altered to obtain data not specified by the original token.

Re-authenticating?  Oh yes.  There needs to be some sort of authentication scheme that allows the user to obtain a token by logging in someplace.  This is up to the system designer to decide how it is accomplished.  There may be a login id and password that the user uses to get a temporary key and access an API by hand (usually using an interface like Swashbuckle/Swagger).  For machine-to-machine communications other protocols can be used.  A token can also be issued for a longer time period for client use.

The token use can be narrowed using the issuer and audience.  If your company has many APIs that are used for different purposes, you might issue a token that is restricted for use on one API.  You can setup your API to reject any token that is not issued by your security API and you can reject tokens where the audience in the token is not serviced by the API.

Let’s say that you want to communicate from one API to another, how would you use the JWT token?

To use the token, you need to put it in the authorization header of the API call:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

When you generate your token, you should set the expire time to something like one to four hours.  Once you obtain a token from your source (either you generate the token or you get it from a security API), then you save the token in a cache.  Many articles talk about using a cookie, but an API will typically not use cookies.  If you have only one API instance, you can get away with using a singleton class to save your token.  If you plan to load-balance two or more instances of your API (plan ahead, assume you’ll need to scale up in the future), then you’ll want to store the token in a cache system (such as Redis or Memcached).

When you grab the token from your cache, check the expire and replace the token if it only has a couple of minutes left.  There could be network delays when sending your token to the remote API, even if it’s in the same data center.  If you wait until the last second to renew the token, you’ll run into issues where the consuming API will reject your token.  This problem will increase when your network is experiencing an unexpected latency.

For your consuming API, you must check the signature first.  There is no need to accept a JWT token that has a bad signature.  That just indicates that someone changed the payload data manually.  Once that has been verified, then check the expire date/time and make sure the token is still valid.  Next, you’ll want to check any other restrictions placed on the token (audience and issuer).

What Else is in the Token?

You can store data inside the token.  There is no limit, but you should keep the token as small as possible.  Don’t pass around a 10 megabyte token and expect a fast network.  You should pass some authorization information of the person or machine that authenticated (i.e. user id, claims).  By doing this, you can form a state-less website.  Your front-end might keep the token in a cookie after the user logs in.  That token is then used in the bearer authorization header for every call to your website back-end.  This eliminates the need for a website session (i.e. session-less or state-less).  For this use case, you can have the authenticated user’s id or some sort of temporary key contained in the payload (i.e. generate a new temporary key when the user logs in and store it in the user table, then throw it away when the user logs out).

The data that you store in the payload should be something that is used repeatedly by the APIs or website you are accessing.  Otherwise, if you try to store something like the current page number in the JWT token, then a new token will have to be issued every time you click the “next” button to get a page of data.  If you’re looking for a place to store temporary state variables, I would recommend putting them in a cache and keying the cache to the user id.  Once the token has been authenticated, the user id can be used to grab the data from your cache and you can continue as though you had a session.

Why Use a Token?

When I create a new API, I have a check-list of what goes into the shell of the API:

  1. JWT Token authentication management for all calls
  2. Logger
  3. Help screen (swashbuckle/swagger)
  4. IOC container

No Web API should be without these items.  My use of the help screen allows me to document my API and gives me a method of testing the API directly.  The logger will be necessary to troubleshoot problems and track exceptions once the API is deployed to an environment in the data center.  The IOC container is the framework that allows developers to use unit tests with ease.  Last, but not least, never deploy an API without some sort of security.  Unless you want the entire world to be able to access it.  Install and test your JWT token security first, then you can add controllers and business logic without worrying about a hacker accessing your data before your API goes live (I’m assuming that you might deploy an API for a feature that is turned off).

You might be thinking that your data is open to the public anyway.  Why secure your API?  You might want to limit access to your data via your website or mobile device interface.  If your API is open to the world, some entity, could tap into your API without your knowledge and put a load on your system that you don’t expect.  Don’t assume anything.  A random Facebook developer could create an application that accesses your API and then a half-million Facebook users unwittingly hit your API when they use that app.  Yikes!

If you want the world to have access to your API, then you better be prepared to scale.

 

Versioning Your APIs

Introduction

If you’ve ever written an API and used it in a real-world application, you’ll discover the need to make changes to enhance your software.  The problem with changing an API is that once the interface has been published and used by other applications, the end points cannot be changed.  The best way to deal with this problem is to version your API so that a new version can have different end points.  This will give consumers time to change their code to match the new versions.

One sensitive consumer of API data is the mobile application.  If your company produces mobile applications, then you’ll need to deploy the new mobile app to the app store after the API has been deployed and is able to consume requests.  This creates a chicken or the egg problem of which should go first.  If the API is versioned, then it can be deployed in advance of the mobile application being available for download.  The new mobile app can use the new version of the API while the older mobile app versions still consume data from the previous versions of your API.  This can also avoid the problem of forcing your end users to upgrade ASAP.

Versioning Method 1

To version your API, there is an obvious but painful method of versioning.  This involves using a feature in IIS that allows multiple applications to be created under one website.  The process is to make a copy of the previous version of your API, then make changes to the code to represent the next version of the API.  Next, create a new application in IIS, say “V2.0”.  Then the path to your API will be something like “myapi.com/V2.0/controllername/method”.

Here is a list of the drawbacks to this method:

  • Deployment involves the creation of a new application every time a new version is deployed.
  • Any web.config file in the root directory of IIS would be inherited by all applications.
  • Keeping multiple versions of code becomes difficult to track.
  • Continuous integration becomes a headache because each version will need a deployment.

Several of these issues can be “fixed” by using creative merging/splitting of branches.  The inheritance problem can be fixed by leaving the root directory empty.  The creation of new applications under IIS can be automated through Powershell scripting (deployment process can check if app exists and create it if it doesn’t).

Versioning Method 2

A NuGet package that can be added to your solution to allow automatic versioning of controllers (here’s the package for .Net Core).  There is a great blog post on this package here.  I looked over the blog post and decided to do a little testing of my own.  I tested a sample Web API project for .Net Core to see if I could get the same results as duplicating projects and installing them as applications under IIS.  This is what I came up with for my version 2 controller:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace WebApiVersionedSample.Controllers
{
  [ApiVersion("2.0")]
  [ApiVersion("2.1")]
  [Route("v{version:apiVersion}/Values")]
    public class Values2Controller : Controller
    {
      [HttpGet, MapToApiVersion("2.0")]
      public IEnumerable GetV20()
      {
          return new string[] { "value1 - version 2", "value2 - version 2" };
      }

      [HttpGet, MapToApiVersion("2.1")]
      public IEnumerable GetV21()
      {
        return new string[] { "value1 - version 2.1", "value2 - version 2.1" };
      }

      [HttpGet("{id}", Name = "Get"), MapToApiVersion("2.0")]
      public string Get20(int id)
      {
          return $"id={id} version 2.0";
      }

      [HttpGet("{id}", Name = "Get"), MapToApiVersion("2.1")]
      public string Get21(int id)
      {
        return $"id={id} version 2.1";
      }
    }
}

As you can see, I set this up to accept version 2.0 or version 2.1, and I removed the “api” default path.  If you specify version 2.0, your consumer application can only see the GetV20 method for a get operation and your application will see Get20(int id) for any get method that passes and integer id variable.  In my sample code, I only printed the version number to show what code was executed when I selected a particular version.  Normally, you’ll call a business class from your method and that business class can be shared between two or more versions if the functionality didn’t change.  If, however, you have different logic in your business class between version 2.0 and version 2.1, then you’ll need to create another business class to call from your get method for version 2.1 and leave your version 2.0 untouched.

If you want to keep things simple, you can start a new version by creating new controllers for each endpoint and just add the version number to the end of the name.  Then you can change any one or more get, post, put or delete to conform to your new version.  Just be aware that this logic will need to continue into your business classes if necessary.

For my version 1.0 controller, as an example, I used the ValuesController object with an attribute at the top like so:

[ApiVersion("1.0")]
[Route("v{version:apiVersion}/Values")]
public class ValuesController : Controller

The “Route” shows how the version number precedes “/Values” controller name.  To access this in your browser hit F5 and change the version number.

Example: “http://localhost:64622/v1.0/values” or “http://localhost:64622/v2.1/values”.

To change your startup browser location, expand your properties and double-click on the launchSettings.json file:

Now you can change the application url and the launchUrl:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:64622/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "v1.0/values",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApiVersionedSample": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "v1.0/values",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:64623/"
    }
  }
}

This method of versioning your API has a few advantages over the previous method:

  • Deployments are set.  Add new version code and re-deploy.
  • No need to keep multiple copies of source code.
  • No IIS changes are necessary.

There are some potential pitfalls that developers will need to be aware of.  One complex situation is the possibility of a database change.  This can ripple down to a change to your Entity Framework POCOs, and possibly your context object.  If you are cautious and add non-breaking changes (like adding a new field), then you can change your database repository code without breaking your previous versions.  If you have breaking changes (such as a change to a stored procedure), then you’ll need to get creative and design it so both the old version and new version of your code still work together.

Where to Find the Code

You can download the sample code used in this blog post by going to my GitHub account (click here).