Search code examples
c#jwtbase64base64url

Could not decode JWT payload from base64


I'm going to decode a JWT token from request header, it looks like this:

eyJzdWIiOiIxIiwiZXZlbnRfaWQiOiI3ZTA3Y2JmNC0wYjYyLTQ1MzMtYmE5ZC1mZGFjNDkyNTNjZTUiLCJpYXQiOiIxNTkwODk4Mzg1IiwiZXhwIjoiMTU5MDkwMTk4NSIsImlzcyI6ImxvY2FsaG9zdDo0NDM4NyIsInRpbWV6b25lX29mZnNldCI6LTcsInVzciI6Im1pbmcuaGlldS4xMzEyIiwiYWxpYXMiOiJNaW5nIEhpZXUiLCJwaG9uZSI6IjA4NDQ1OTAyNTIiLCJlbWFpbCI6ImhpZXVhbWlAZ21haWwuY29tIn0

public static string Base64Decode(string base64EncodedData)
{
    var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
    return Encoding.UTF8.GetString(base64EncodedBytes);
}

When passing the token above to decode method, it throws an exception that tells:

Invalid length for a Base-64 char array or string

dotnetfiddle referrence: https://dotnetfiddle.net/Z2TUz9

But when using it in javascript (using atob function), it works properly.

Could anyone tell me why, then tell me how can I decode it in C#?


Solution

  • Before I get into detail about the question, I would generally suggest using a JWT library that can do all that needs to be done with a few function calls.

    As a Base64 string, it is indeed too short. A valid Base64 encoded string should have a length that is dividable by 4 and should be padded with 1 or 2 padding characters = if necessary. But JWT uses the slightly different Base64url encoding and in this encoding padding is optional.

    But the C# Base64 decoder is quite strict in this regard. Therefore you need to convert from Base64Url to Base64 and add the missing padding. Besides that, there are also two Base64Url specific characters that need to be converted back to Base64, as shown in the following code:

    using System;
                        
    public class Program
    {
        public static void Main()
        {
            string token = "eyJzdWIiOiIxIiwiZXZlbnRfaWQiOiI3ZTA3Y2JmNC0wYjYyLTQ1MzMtYmE5ZC1mZGFjNDkyNTNjZTUiLCJpYXQiOiIxNTkwODk4Mzg1IiwiZXhwIjoiMTU5MDkwMTk4NSIsImlzcyI6ImxvY2FsaG9zdDo0NDM4NyIsInRpbWV6b25lX29mZnNldCI6LTcsInVzciI6Im1pbmcuaGlldS4xMzEyIiwiYWxpYXMiOiJNaW5nIEhpZXUiLCJwaG9uZSI6IjA4NDQ1OTAyNTIiLCJlbWFpbCI6ImhpZXVhbWlAZ21haWwuY29tIn0";
            token = token.Replace('_', '/').Replace('-', '+');
            switch (token.Length % 4)
            {
                case 2: token += "=="; break;
                case 3: token += "="; break;
            }       
            var decoded = Convert.FromBase64String(token);
            var decodedToken = System.Text.Encoding.Default.GetString(decoded);     
            Console.WriteLine(decodedToken);
        }
    }
    

    Code in dotnetfiddle

    The datatype of decoded is byte[] and the output would be just the name of the type. To convert it to string and print the JSON I added another line.

    The next step from here would be to convert the JSON to a C# object or to use a library as mentioned in the beginning.