Tags

, , , , ,

An authentication server provides a client with a JSON Web Token, and the authentication server will also handle requests from application servers to verify tokens supplied by clients.

Algorithm

Generally, the token generation code follows this process:

  • 1. Initialise the token header as a set of JSON objects.
  • 2. Initialise the token payload as a set of JSON objects.
  • 3. Base64-encode the header and payload independently. This gives us the unsigned token.
  • 4. Using the HMAC SHA256 algorithm, and a secret key value, generate the signature for the unsigned payload.

A token, therefore, will have three segments: a) header, b) payload, and c) signature. The first two are Base64-encoded JSON objects, and the third is the encoded signature of the first two segments. This can be seen in action when generating a token with the debugger at jwt.io:


https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5
cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gR
G9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36P
Ok6yJV_adQssw5c

When decoded, the token would look something like this:


{ "alg": "HS256", "typ": "JWT" }
{ "sub": "Web Application", "name": "Michael", "iat": 45435334 }
{ SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c }

.NET Implementation

When working with .NET, one could use System.IdentityModel.Tokens.Jwt, but it can also be done using Newtonsoft.Json and System.Security.Cryptography.

I defined the header properties in a TokenHeader class:


public class TokenHeader
{
public string alg { get; set; }
public string typ { get; set; }
}

Instantiating the TokenHeader class in the main method, we can declare static variables for the objects:


TokenHeader tokenHeader = new TokenHeader();
tokenHeader.alg = "HS256";
tokenHeader.typ = "JWT";

The variables are formatted as JSON objects, then Base64-encoded:


string headerString = JsonConvert.SerializeObject(tokenHeader);
string encodedHeaderString = ConvertHeaderToJson(headerString);

private static string ConvertHeaderToJson(string headerString)
{
byte[] headerStringAsBytes = Encoding.ASCII.GetBytes(headerString);
string encodedHeaderString = Convert.ToBase64String(headerStringAsBytes);
return encodedHeaderString;
}

For generating the third segment of the token – the signature – the process is different. In this case, we need to generate a hash digest of the header and payload, along with a 256-bit secret value, then encode that digest. The algorithm for this is given as:


HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload), your-256-bit-secret
)

This algorithm is implemented by the following code:


string message = encodedHeaderString + "." + encodedPayloadString;
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(myKey);

HMACSHA256 hmacsha256 = new HMACSHA256(keyByte);

byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
string hashAsString = BitConverter.ToString(hashmessage);

byte[] signatureStringAsBytes = Encoding.ASCII.GetBytes(hashAsString);
string encodedSignature = Convert.ToBase64String(signatureStringAsBytes);
return encodedSignature;

JavaScript Implementation

Several JavaScript libraries are needed for the implementation here. The crypto ones are referenced on Joe Kampschmidt’s blog:

  • jquery-3.3.1.min.js
  • jquery.base64.min.js
  • crypto-js.min.js
  • hmac-sha256.min.js
  • enc-base64.min.js

To initialise the header and payload as JSON objects, JSON.parse() is used.


var headerjson = '{ "alg": "HS256", "typ": "JWT" }',
headerobj = JSON.parse(headerjson);

var payloadjson = '{ "sub": "x555", "name": "Michael", "iat": 445644543534, "issued": ' + Math.floor(Date.now() / 1000) + ' }',
payloadobj = JSON.parse(payloadjson);

Next, independently encode the header and the payload:


headerb64 = btoa(unescape(encodeURIComponent(headerjson)));
headerb64str = decodeURIComponent(escape(window.atob(headerb64)));

payloadb64 = btoa(unescape(encodeURIComponent(payloadjson)));
payloadb64str = decodeURIComponent(escape(window.atob(payloadb64)));

The unsigned token will consist of two segments, one for the encoded header and the other the encoded payload:
var unsignedToken = headerb64 + "." + payloadb64;

Finally, the crypto libraries provide the HMAC SHA256 algorithm used here for signing the token:


var secretKey = "Password1";
var tokenSignature = CryptoJS.HmacSHA256(unsignedToken, secretKey);
var encodedTokenSignature = CryptoJS.enc.Base64.stringify(tokenSignature);
gentoken.value = encodedTokenSignature;

And finaly, I’ve put all three segments together to form the signed token:
allsegments.value = headerb64 + "." + payloadb64 + "." + encodedTokenSignature;

Get the .NET and JavaScript code here…