biscuit-java icon indicating copy to clipboard operation
biscuit-java copied to clipboard

codecs: add base64 URL encoding without paddin

Open KannarFr opened this issue 3 months ago • 3 comments

What

Adds serializeBase64UrlNoPadding() methods to embed biscuit tokens in URL parameters without padding characters safely (=).

Why

Padding characters in base64-encoded tokens can cause issues when used in URLs. This was mentioned in code comments about needing custom encoders to prevent Java's default padding in URL contexts.

How

  • Added serializeBase64UrlNoPadding() to Biscuit and UnverifiedBiscuit classes
  • Uses Java's built-in Base64.getUrlEncoder().withoutPadding()
  • Existing fromBase64Url() already handles both formats automatically
  • Updated docs to clarify that padded/unpadded strings are both accepted

Example

String token = biscuit.serializeBase64UrlNoPadding();
String url = "https://api.example.com/auth?token=" + token;
// No special encoding needed - works directly in URLs

Fully backward compatible, no breaking changes.

KannarFr avatar Oct 15 '25 15:10 KannarFr

We need to check the compatibility with the other library. https://github.com/eclipse-biscuit/biscuit-rust/issues/211 https://github.com/eclipse-biscuit/biscuit-rust/pull/213.

The implementation are not all coherent https://eprint.iacr.org/2022/361.pdf

Korbik avatar Oct 17 '25 11:10 Korbik

@Korbik, I did not test all libraries, but biscuit-cli (so biscuit-rust) can decode it.

KannarFr avatar Oct 17 '25 11:10 KannarFr

I really recommend reading the paper to get a good understanding of the issues. One thing we want to avoid is malleability (changing the base64 representation without changing the underlying data). This is an issue if intermediaries want to compare base64 contents directly. The most obvious way to do that is to manipulate padding characters. Another less obvious way is to manipulate unused bits (eg swapping a Q with an R, see the paper for how this works).

Another thing we want to avoid is breaking compatibility with other libraries.

To give you a quick summary:

  • the spec mandates base64 url for text representations (but does not say anything about padding)
  • currently, all (i think) implementations emit padded base64

rust

  • the rust implementation uses base64 0.13 with the URL_SAFE config, which accepts both padded and unpadded versions when decoding
  • recent base64 versions (0.20+) mandate the presence of padding characters, so when we update it, unpadded versions will be rejected
  • there is also the stricter base64-ct in the dependency tree, which does not treat padding as optional. we might want to use it directly to reduce the dependency footprint

Go

  • the go implementation (last time i checked) does not treat padding as optional

haskell

  • the haskell implementation uses a version of base64 with optional padding

conclusion

  • malleability is not directly an issue for biscuits, since we use hex encoding for things where we need strict equality (pubkeys, revocation ids)
  • The ecosystem seems to be moving towards explicit padding, to avoid malleability issues. We should not rely on libraries treating padding as optional.
  • base64 is hopeless
  • we could add encoding and decoding functions with explicit no_padding behaviour, but:
  • for base64, the biscuit ecosystem is more or less set on padding
  • an alternative to base64 with stricter semantics and no chance of overlap would be good

divarvel avatar Oct 23 '25 10:10 divarvel