Skip to content

base64url encoding

October 17, 2014

It’s often more convenient to manage data in text format rather than binary data (for example a string column in a database, or a string rendered into a HTTP response). Common examples in security are digital signatures and encryption. Signing and encrypting typically produce bytes of data and in a web application sometimes it’s just easier to manage that data as text.

Base64 is a useful tool for doing this encoding. The only problem is that base64 encoding uses characters that do not work well in URLs and sometimes HTTP headers (e.g. the +, / and = characters are either reserved or have special meaning in URLs). URL encoding is designed to address that problem, but it’s sometimes error prone (e.g. double encoding) or the tooling just doesn’t do the right thing (IIS decodes %2F into a / before it arrives into the application and thus confuses the ASP.NET routing framework). It is very useful to put these sorts of values in a URL, but it’s also frustrating that it’s problematic and that we have to work around these issues again and again.

While reading the JWT specs they faced the same problem and they addressed it by using base64url encoding (which is almost the same, yet different than base64 encoding). Base64url encoding is basically base64 encoding except they use non-reserved URL characters (e.g. – is used instead of + and _ is used instead of /) and they omit the padding characters. I’ve been using this for some time now and am quite happy with it as a replacement for base64 encoding.

Unfortunately there’s no implementation (that I know of) in the .NET framework for this, so we’ve built our own in our Thinktecture.IdentityModel security helper library. You can use our helpers by using the NuGet, or you can grab the code from here, or you can just copy from the snippet below.

public static class Base64Url
{
    public static string Encode(byte[] arg)
    {
        string s = Convert.ToBase64String(arg); // Standard base64 encoder
            
        s = s.Split('=')[0]; // Remove any trailing '='s
        s = s.Replace('+', '-'); // 62nd char of encoding
        s = s.Replace('/', '_'); // 63rd char of encoding
            
        return s;
    }

    public static byte[] Decode(string arg)
    {
        string s = arg;
        s = s.Replace('-', '+'); // 62nd char of encoding
        s = s.Replace('_', '/'); // 63rd char of encoding
            
        switch (s.Length % 4) // Pad with trailing '='s
        {
            case 0: break; // No pad chars in this case
            case 2: s += "=="; break; // Two pad chars
            case 3: s += "="; break; // One pad char
            default: throw new Exception("Illegal base64url string!");
        }
            
        return Convert.FromBase64String(s); // Standard base64 decoder
    }
}

Edit: Turns out there are two places in .NET where this sort of functionality is available: 1) ASP.NET’s HttpServerUtility.UrlTokenEncode, and 2) Katana’s Microsoft.Owin.Security assembly with the Base64UrlTextEncoder class.

8 Comments leave one →
  1. twomm permalink
    October 20, 2014 11:25 am

    if you are ok with padding chars you could use System.Web.HttpServerUtility.UrlTokenEncode

    • October 21, 2014 4:40 pm

      Wow, amazing that’s been in ASP.NET so long and I’ve not seen it. Thanks.

  2. RonyK permalink
    November 3, 2014 9:11 am

    So this extension class does no longer exists in the IdentityModel repository, correct?

  3. September 23, 2015 8:16 am

    Need the same for ASP classic, do you have a clue ? thanks

    • October 1, 2015 5:12 pm

      The code would be easly to implement in VBScript, I imagine. But I’ve not done it, sorry.

  4. entilzha permalink
    November 8, 2016 3:31 pm

    We used the bitoftech blog (Taiseer Joudeh) to give us a leg up on our oauth implementation. He used “TextEncodings.Base64Url.Decode(..)” but we encountered a problem with the special characters Brock mentions above. So we switched to “TextEncodings.Base64.Decode(..)” (NOTE the remove of “Url” after “Base64”) and everything seems to be working fine. Unless there is something different we need from Brock’s implementation that someone can point out.

  5. Aleksandar permalink
    December 20, 2016 5:17 am

    Careful about UrlTokenEncode it is not the same as the code above.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: