Skip to content

Conversation

@KannarFr
Copy link
Contributor

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.

@Korbik
Copy link
Contributor

Korbik commented Oct 17, 2025

We need to check the compatibility with the other library.
eclipse-biscuit/biscuit-rust#211
eclipse-biscuit/biscuit-rust#213.

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

@KannarFr
Copy link
Contributor Author

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

@divarvel
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants