Search code examples
dartbase64url

Do I need to manually remove the = padding from a Base64Url encoded string in Dart?


I was surprised to notice that when I converted a string to Base64Url in Dart I got a string that ended with an = padding character.

import 'dart:convert';

main() {
  String credentials = "username:password";
  String encoded = base64Url.encode(utf8.encode(credentials)); 

  print(encoded);  // dXNlcm5hbWU6cGFzc3dvcmQ=
}

I thought that the point of Base64Url was to remove the characters that would not not be good in a URL. Apparently not. The docs even have it listed. So does that mean I have to manually remove it myself?

final noPadding = encoded.replaceAll(RegExp('='), ''); // dXNlcm5hbWU6cGFzc3dvcmQ

Solution

  • The spec for base64url (URL and filename safe) only replaces the 62nd (+) and 63rd (/) characters of normal base64 with - and _, respectively. It does not replace the padding character (=), but instead makes this statement:

    The pad character "=" is typically percent-encoded when used in an URI, but if the data length is known implicitly, this can be avoided by skipping the padding.

    While it is possible to remove the padding, you have to be careful because that is not handled automatically and the decode method will throw an error if you don't make sure to restore the padding first by using something like normalize().

    I would instead recommend to just use percent encoding which is available in the Uri class, as the Dart base64 implementation already supports percent-encoded strings automatically:

    import 'dart:convert';
    
    main() {
      String input = 'username:password';
      String encoded = Uri.encodeComponent(base64Url.encode(utf8.encode(input)));
      print(encoded); // dXNlcm5hbWU6cGFzc3dvcmQ%3D
      String decoded = utf8.decode(base64Url.decode(encoded));
      print(decoded); // username:password
    }
    

    Additionally, if you are passing the base64url encoded strings as part of a URL it makes sense to use percent-encoding anyway because that is expected behavior in a URL and preserves the entire string so it doesn't have to be normalized later.