Skip to content

Instantly share code, notes, and snippets.

@shawty
Created April 11, 2019 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawty/4e91282e6b3bf35402856e84ec39011b to your computer and use it in GitHub Desktop.
Save shawty/4e91282e6b3bf35402856e84ec39011b to your computer and use it in GitHub Desktop.
Quick and dirty JWT Token decoder class to use in Blazor based projects, since trying to use the official MS Jwt Token libs at present causes things to blow up. :-)
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace IntranetV6.Client.Classes
{
public static class StringExtensions
{
public static int GetNextHighestMultiple(this int source, int multipicand)
{
int result = source;
while ((result % multipicand) != 0)
{
result++;
}
return result;
}
}
// Shamelessly ripped from the MS implementation :-)
public struct JwtRegisteredClaimNames
{
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Actort = "actort";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Typ = "typ";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Sub = "sub";
//
// Summary:
// http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout
public const string Sid = "sid";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Prn = "prn";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Nbf = "nbf";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Nonce = "nonce";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string NameId = "nameid";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Jti = "jti";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Iss = "iss";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Iat = "iat";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string GivenName = "given_name";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string FamilyName = "family_name";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Gender = "gender";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Exp = "exp";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Email = "email";
//
// Summary:
// http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
public const string AtHash = "at_hash";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string CHash = "c_hash";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Birthdate = "birthdate";
//
// Summary:
// http://openid.net/specs/openid-connect-core-1_0.html#IDToken
public const string Azp = "azp";
//
// Summary:
// http://openid.net/specs/openid-connect-core-1_0.html#IDToken
public const string AuthTime = "auth_time";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Aud = "aud";
//
// Summary:
// http://openid.net/specs/openid-connect-core-1_0.html#IDToken
public const string Amr = "amr";
//
// Summary:
// http://openid.net/specs/openid-connect-core-1_0.html#IDToken
public const string Acr = "acr";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string UniqueName = "unique_name";
//
// Summary:
// http://tools.ietf.org/html/rfc7519#section-4
public const string Website = "website";
//
// Summary:
// Microsoft have to be different, if you want to use roles for auth in the API, you have to use this
// rather than the ietf standard "Role"..... (Added by shawty, as not in official JWT constants list)
public const string Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
}
public class JwtDecoder
{
private Dictionary<string, object> _header;
private Dictionary<string, object> _payload;
private string _token = String.Empty;
public JwtDecoder(string token, bool autoDecode = false)
{
_token = token;
if (autoDecode) Decode();
}
public void Decode()
{
string[] parts = _token.Split('.');
if (parts.Length != 3) throw new Exception("Malformed JWT token");
string b64Header = parts[0];
string b64Payload = parts[1];
// B64 strings must be a length that is a multiple of 4 to decode them, so ensure this before we try to use them
if (b64Header.Length % 4 != 0)
{
var lengthToBe = b64Header.Length.GetNextHighestMultiple(4);
b64Header = b64Header.PadRight(lengthToBe, '=');
}
if (b64Payload.Length % 4 != 0)
{
var lengthToBe = b64Payload.Length.GetNextHighestMultiple(4);
b64Payload = b64Payload.PadRight(lengthToBe, '=');
}
string headerJson = Encoding.UTF8.GetString(Convert.FromBase64String(b64Header));
string payloadJson = Encoding.UTF8.GetString(Convert.FromBase64String(b64Payload));
_header = JsonConvert.DeserializeObject<Dictionary<string, object>>(headerJson);
_payload = JsonConvert.DeserializeObject<Dictionary<string, object>>(payloadJson);
}
public object GetKey(string keyName)
{
if (!_payload.ContainsKey(keyName)) throw new Exception($"JWT Token does not contain key {keyName}");
return _payload[keyName];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment