codec_base64url/decode.rs
1// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use base64::{decoded_len_estimate, engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
6use zeroize::Zeroizing;
7
8use crate::Base64UrlError;
9
10/// Decode RFC 4648 section 5 Base64URL without padding.
11pub fn base64url_to_bytes(s: &str) -> Result<Vec<u8>, Base64UrlError> {
12 base64url_bytes_to_bytes(s.as_bytes())
13}
14
15/// Decode RFC 4648 section 5 Base64URL bytes without padding.
16///
17/// This is useful for compact JWT/JWS/JWE segments that have already been
18/// split as bytes. It avoids requiring callers to first prove UTF-8 just to
19/// decode an ASCII Base64URL alphabet.
20pub fn base64url_bytes_to_bytes(bytes: &[u8]) -> Result<Vec<u8>, Base64UrlError> {
21 // Retain the partially decoded allocation until validation completes so
22 // malformed input cannot leave decoded material in a freed heap block.
23 let mut output = Zeroizing::new(vec![0_u8; decoded_len_estimate(bytes.len())]);
24 let length = URL_SAFE_NO_PAD
25 .decode_slice(bytes, output.as_mut_slice())
26 .map_err(|_| Base64UrlError::Invalid)?;
27 output.truncate(length);
28 Ok(core::mem::take(&mut *output))
29}