From ee50c7d6bb206348e043771a6f30c403f5344ac6 Mon Sep 17 00:00:00 2001
From: Alexander Korolev <alexander.korolev.germany@gmail.com>
Date: Sun, 17 Sep 2023 17:54:48 +0200
Subject: [PATCH] fixed regression in at_hash behavior

---
 src/claims.rs | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/src/claims.rs b/src/claims.rs
index 9a4c3a5..82f2876 100644
--- a/src/claims.rs
+++ b/src/claims.rs
@@ -1,8 +1,16 @@
 use crate::Userinfo;
-use base64::{engine::general_purpose::URL_SAFE, Engine as _};
+use base64::{
+    alphabet,
+    engine::{GeneralPurpose, GeneralPurposeConfig},
+    Engine as _,
+};
 use biscuit::SingleOrMultiple;
 use url::Url;
 
+const ANYPAD: GeneralPurposeConfig = GeneralPurposeConfig::new()
+    .with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent);
+const URL_SAFE_ANYPAD: GeneralPurpose = GeneralPurpose::new(&alphabet::URL_SAFE, ANYPAD);
+
 /// The primary extension that OpenID Connect makes to OAuth 2.0 to enable End-Users to be Authenticated is the ID Token data structure. The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims. The ID Token is represented as a JSON Web Token (JWT) [JWT].
 pub trait Claims {
     /// Issuer Identifier for the Issuer of the response. The iss value is a case sensitive URL using the https scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components.
@@ -39,7 +47,7 @@ pub trait Claims {
     ///
     /// The returned Vec is the first 128 bits of the access token hash using alg's hash alg
     fn at_hash_to_vec(&self) -> Option<Vec<u8>> {
-        URL_SAFE.decode(self.at_hash()?).ok()
+        URL_SAFE_ANYPAD.decode(self.at_hash()?).ok()
     }
     /// Decodes c_hash. Returns None if it doesn't exist or something goes wrong.
     ///
@@ -47,6 +55,20 @@ pub trait Claims {
     ///
     /// The returned Vec is the first 128 bits of the code hash using alg's hash alg
     fn c_hash_to_vec(&self) -> Option<Vec<u8>> {
-        URL_SAFE.decode(self.c_hash()?).ok()
+        URL_SAFE_ANYPAD.decode(self.c_hash()?).ok()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn decode_at_hash() {
+        let x = URL_SAFE_ANYPAD.decode("zglPCMCEP7ilF3LP_NExow");
+        let y = URL_SAFE_ANYPAD.decode("zglPCMCEP7ilF3LP_NExow==");
+        assert!(x.is_ok());
+        assert!(y.is_ok());
+        assert_eq!(x, y);
     }
 }