C# - How To Read a JWT

Nuget Requirements

  1. System.IdentityModel.Tokens.Jwt
  2. Newtonsoft

Intro

Very simple bit of code shows you how to use IdentityModel.Tokens.Jwt built in methods to quickly break down your token into useful data. You could have just returned a serialized version of Token but knowing a bit of the underlying structure I wanted to only return values I intended to use later on - namely the payload and any custom headers.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;

namespace JwtReaderExample
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var jwt = "REDACTED-SUPPLY-YOUR-OWN";

            var decodedJwt = await ReadTokenAsync(jwt);

            await Console.Out.WriteLineAsync(decodedJwt);
            await Console.In.ReadLineAsync();
        }

        public static string ReadToken(string jwtInput)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            var jwtOutput = string.Empty;

            // Check Token Format
            if (!jwtHandler.CanReadToken(jwtInput)) throw new Exception("The token doesn't seem to be in a proper JWT format.");

            var token = jwtHandler.ReadJwtToken(jwtInput);

            // Re-serialize the Token Headers to just Key and Values
            var jwtHeader = JsonConvert.SerializeObject(token.Header.Select(h => new { h.Key, h.Value }));
            jwtOutput = $"{{\r\n\"Header\":\r\n{JToken.Parse(jwtHeader)},";

            // Re-serialize the Token Claims to just Type and Values
            var jwtPayload = JsonConvert.SerializeObject(token.Claims.Select(c => new { c.Type, c.Value }));
            jwtOutput += $"\r\n\"Payload\":\r\n{JToken.Parse(jwtPayload)}\r\n}}";

            // Output the whole thing to pretty Json object formatted.
            return JToken.Parse(jwtOutput).ToString(Formatting.Indented);
        }

        public static async Task<string> ReadTokenAsync(string jwtInput)
        {
            return await Task.Run(() =>
            {
                return ReadToken(jwtInput);
            });
        }

        // Optional non-return await, intention is to return a task that is awaited at a higher level.
        // Dev preference
        //public static Task<string> ReadToken(string jwtInput)
        //{
        //    return Task.Run(() =>
        //    {
        //        return ReadToken(jwtInput);
        //    });
        //}
    }
}

Summary

You check the format, open token for reading, and serialize (however you wish) through the values available to you.

Most of the work is really done by Newtonsoft and IdentityModel at this point.

Additional Note UserData Property

Some of the time you want to add non-JWT attributed values into the JWT, things that correspond to a current user. Asp.Net Idenity has this ability during your token generation to set the user data claim. Hopefully, you were smart about this and put it inside an Object and then json deserialized to string and assigned that as the UserData value. This object could contain user related data such as AccountId for example. That spot is going to be located inside the claims under a schema.

var userDataJson = token.Claims
    .Where(c => c.Type.Equals("http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata"))
    .Select(c => c.Value).FirstOrDefault();

var userData = JsonConvert.DeserializeObject<ApiUserData>(userDataJson);

Sources

Jwt.io
Auth0