Quellcode durchsuchen

Refactor MintBuilder (#887)

* Refactor MintBuilder
* Validate azp instead of aud for client id
David Caseria vor 2 Wochen
Ursprung
Commit
f018465aa6

+ 1 - 1
crates/cdk-axum/src/ws/subscribe.rs

@@ -20,7 +20,7 @@ pub(crate) async fn handle(
     let mut subscription = context
         .state
         .mint
-        .pubsub_manager
+        .pubsub_manager()
         .try_subscribe(params)
         .await
         .map_err(|_| WsError::ParseError)?;

+ 1 - 1
crates/cdk-cli/src/sub_commands/cat_device_login.rs

@@ -82,7 +82,7 @@ async fn get_device_code_token(mint_info: &MintInfo, client_id: &str) -> (String
         .expect("Nut21 defined")
         .openid_discovery;
 
-    let oidc_client = OidcClient::new(openid_discovery);
+    let oidc_client = OidcClient::new(openid_discovery, None);
 
     // Get the OIDC configuration
     let oidc_config = oidc_client

+ 1 - 1
crates/cdk-cli/src/sub_commands/cat_login.rs

@@ -93,7 +93,7 @@ async fn get_access_token(
         .expect("Nut21 defined")
         .openid_discovery;
 
-    let oidc_client = OidcClient::new(openid_discovery);
+    let oidc_client = OidcClient::new(openid_discovery, None);
 
     // Get the token endpoint from the OIDC configuration
     let token_url = oidc_client

+ 1 - 1
crates/cdk-cli/src/sub_commands/mint_blind_auth.rs

@@ -164,7 +164,7 @@ async fn refresh_access_token(
         .ok_or_else(|| anyhow::anyhow!("OIDC discovery information not available"))?
         .openid_discovery;
 
-    let oidc_client = OidcClient::new(openid_discovery);
+    let oidc_client = OidcClient::new(openid_discovery, None);
 
     // Get the token endpoint from the OIDC configuration
     let token_url = oidc_client.get_oidc_config().await?.token_endpoint;

+ 11 - 2
crates/cdk-common/src/common.rs

@@ -162,8 +162,8 @@ impl PaymentProcessorKey {
     }
 }
 
-/// Secs wuotes are valid
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
+/// Seconds quotes are valid
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
 pub struct QuoteTTL {
     /// Seconds mint quote is valid
     pub mint_ttl: u64,
@@ -178,6 +178,15 @@ impl QuoteTTL {
     }
 }
 
+impl Default for QuoteTTL {
+    fn default() -> Self {
+        Self {
+            mint_ttl: 60 * 60, // 1 hour
+            melt_ttl: 60,      // 1 minute
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use std::str::FromStr;

+ 16 - 16
crates/cdk-integration-tests/src/init_auth_mint.rs

@@ -31,14 +31,10 @@ where
 
     let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
 
-    let mut mint_builder = MintBuilder::new();
+    let mut mint_builder = MintBuilder::new(Arc::new(database));
 
-    mint_builder = mint_builder
-        .with_localstore(Arc::new(database))
-        .with_keystore(Arc::new(key_store));
-
-    mint_builder = mint_builder
-        .add_ln_backend(
+    mint_builder
+        .add_payment_processor(
             CurrencyUnit::Sat,
             PaymentMethod::Bolt11,
             MintMeltLimits::new(1, 300),
@@ -46,10 +42,14 @@ where
         )
         .await?;
 
-    mint_builder =
-        mint_builder.set_clear_auth_settings(openid_discovery, "cashu-client".to_string());
+    let auth_database = Arc::new(auth_database);
 
-    mint_builder = mint_builder.set_blind_auth_settings(50);
+    mint_builder = mint_builder.with_auth(
+        auth_database.clone(),
+        openid_discovery,
+        "cashu-client".to_string(),
+        vec![],
+    );
 
     let blind_auth_endpoints = vec![
         ProtectedEndpoint::new(Method::Post, RoutePath::MintQuoteBolt11),
@@ -71,6 +71,8 @@ where
                 acc
             });
 
+    mint_builder = mint_builder.with_blind_auth(50, blind_auth_endpoints.keys().cloned().collect());
+
     let mut tx = auth_database.begin_transaction().await?;
 
     tx.add_protected_endpoints(blind_auth_endpoints).await?;
@@ -85,15 +87,13 @@ where
 
     tx.commit().await?;
 
-    mint_builder = mint_builder.with_auth_localstore(Arc::new(auth_database));
-
     let mnemonic = Mnemonic::generate(12)?;
 
-    mint_builder = mint_builder
-        .with_description("fake test mint".to_string())
-        .with_seed(mnemonic.to_seed_normalized("").to_vec());
+    mint_builder = mint_builder.with_description("fake test mint".to_string());
 
-    let _mint = mint_builder.build().await?;
+    let _mint = mint_builder
+        .build_with_seed(Arc::new(key_store), &mnemonic.to_seed_normalized(""))
+        .await?;
 
     todo!("Need to start this a cdk mintd keeping as ref for now");
 }

+ 15 - 23
crates/cdk-integration-tests/src/init_pure_tests.rs

@@ -10,7 +10,7 @@ use async_trait::async_trait;
 use bip39::Mnemonic;
 use cashu::{MeltQuoteBolt12Request, MintQuoteBolt12Request, MintQuoteBolt12Response};
 use cdk::amount::SplitTarget;
-use cdk::cdk_database::{self, WalletDatabase};
+use cdk::cdk_database::{self, MintDatabase, WalletDatabase};
 use cdk::mint::{MintBuilder, MintMeltLimits};
 use cdk::nuts::nut00::ProofsMethods;
 use cdk::nuts::{
@@ -227,25 +227,22 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
     // Read environment variable to determine database type
     let db_type = env::var("CDK_TEST_DB_TYPE").expect("Database type set");
 
-    let mut mint_builder = match db_type.to_lowercase().as_str() {
-        "memory" => MintBuilder::new()
-            .with_localstore(Arc::new(cdk_sqlite::mint::memory::empty().await?))
-            .with_keystore(Arc::new(cdk_sqlite::mint::memory::empty().await?)),
+    let localstore = match db_type.to_lowercase().as_str() {
+        "memory" => Arc::new(cdk_sqlite::mint::memory::empty().await?),
         _ => {
             // Create a temporary directory for SQLite database
             let temp_dir = create_temp_dir("cdk-test-sqlite-mint")?;
             let path = temp_dir.join("mint.db").to_str().unwrap().to_string();
-            let database = Arc::new(
+            Arc::new(
                 cdk_sqlite::MintSqliteDatabase::new(&path)
                     .await
                     .expect("Could not create sqlite db"),
-            );
-            MintBuilder::new()
-                .with_localstore(database.clone())
-                .with_keystore(database)
+            )
         }
     };
 
+    let mut mint_builder = MintBuilder::new(localstore.clone());
+
     let fee_reserve = FeeReserve {
         min_fee_reserve: 1.into(),
         percent_fee_reserve: 1.0,
@@ -258,8 +255,8 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
         0,
     );
 
-    mint_builder = mint_builder
-        .add_ln_backend(
+    mint_builder
+        .add_payment_processor(
             CurrencyUnit::Sat,
             PaymentMethod::Bolt11,
             MintMeltLimits::new(1, 10_000),
@@ -272,23 +269,18 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
     mint_builder = mint_builder
         .with_name("pure test mint".to_string())
         .with_description("pure test mint".to_string())
-        .with_urls(vec!["https://aaa".to_string()])
-        .with_seed(mnemonic.to_seed_normalized("").to_vec());
+        .with_urls(vec!["https://aaa".to_string()]);
 
-    let localstore = mint_builder
-        .localstore
-        .as_ref()
-        .map(|x| x.clone())
-        .expect("localstore");
-
-    let mut tx = localstore.begin_transaction().await?;
-    tx.set_mint_info(mint_builder.mint_info.clone()).await?;
+    let tx_localstore = localstore.clone();
+    let mut tx = tx_localstore.begin_transaction().await?;
 
     let quote_ttl = QuoteTTL::new(10000, 10000);
     tx.set_quote_ttl(quote_ttl).await?;
     tx.commit().await?;
 
-    let mint = mint_builder.build().await?;
+    let mint = mint_builder
+        .build_with_seed(localstore.clone(), &mnemonic.to_seed_normalized(""))
+        .await?;
 
     let mint_clone = mint.clone();
     let shutdown = Arc::new(Notify::new());

+ 2 - 2
crates/cdk-integration-tests/tests/fake_auth.rs

@@ -753,7 +753,7 @@ async fn get_access_token(mint_info: &MintInfo) -> (String, String) {
         .expect("Nutxx defined")
         .openid_discovery;
 
-    let oidc_client = OidcClient::new(openid_discovery);
+    let oidc_client = OidcClient::new(openid_discovery, None);
 
     // Get the token endpoint from the OIDC configuration
     let token_url = oidc_client
@@ -811,7 +811,7 @@ async fn get_custom_access_token(
         .expect("Nutxx defined")
         .openid_discovery;
 
-    let oidc_client = OidcClient::new(openid_discovery);
+    let oidc_client = OidcClient::new(openid_discovery, None);
 
     // Get the token endpoint from the OIDC configuration
     let token_url = oidc_client

+ 3 - 3
crates/cdk-integration-tests/tests/integration_tests_pure.rs

@@ -443,7 +443,7 @@ pub async fn test_p2pk_swap() {
         .collect();
 
     let mut listener = mint_bob
-        .pubsub_manager
+        .pubsub_manager()
         .try_subscribe::<IndexableParams>(
             Params {
                 kind: cdk::nuts::nut17::Kind::ProofState,
@@ -773,7 +773,7 @@ async fn test_concurrent_double_spend_swap() {
 
     // Verify that all proofs are marked as spent in the mint
     let states = mint_bob
-        .localstore
+        .localstore()
         .get_proofs_states(&proofs.iter().map(|p| p.y().unwrap()).collect::<Vec<_>>())
         .await
         .expect("Failed to get proof state");
@@ -870,7 +870,7 @@ async fn test_concurrent_double_spend_melt() {
 
     // Verify that all proofs are marked as spent in the mint
     let states = mint_bob
-        .localstore
+        .localstore()
         .get_proofs_states(&proofs.iter().map(|p| p.y().unwrap()).collect::<Vec<_>>())
         .await
         .expect("Failed to get proof state");

+ 11 - 15
crates/cdk-integration-tests/tests/mint.rs

@@ -29,14 +29,15 @@ async fn test_correct_keyset() {
 
     let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
 
-    let mut mint_builder = MintBuilder::new();
     let localstore = Arc::new(database);
-    mint_builder = mint_builder
-        .with_localstore(localstore.clone())
-        .with_keystore(localstore.clone());
+    let mut mint_builder = MintBuilder::new(localstore.clone());
 
     mint_builder = mint_builder
-        .add_ln_backend(
+        .with_name("regtest mint".to_string())
+        .with_description("regtest mint".to_string());
+
+    mint_builder
+        .add_payment_processor(
             CurrencyUnit::Sat,
             PaymentMethod::Bolt11,
             MintMeltLimits::new(1, 5_000),
@@ -44,18 +45,14 @@ async fn test_correct_keyset() {
         )
         .await
         .unwrap();
+    // .with_seed(mnemonic.to_seed_normalized("").to_vec());
 
-    mint_builder = mint_builder
-        .with_name("regtest mint".to_string())
-        .with_description("regtest mint".to_string())
-        .with_seed(mnemonic.to_seed_normalized("").to_vec());
-
-    let mint = mint_builder.build().await.unwrap();
-    let mut tx = localstore.begin_transaction().await.unwrap();
-
-    tx.set_mint_info(mint_builder.mint_info.clone())
+    let mint = mint_builder
+        .build_with_seed(localstore.clone(), &mnemonic.to_seed_normalized(""))
         .await
         .unwrap();
+    let mut tx = localstore.begin_transaction().await.unwrap();
+
     let quote_ttl = QuoteTTL::new(10000, 10000);
     tx.set_quote_ttl(quote_ttl).await.unwrap();
 
@@ -81,7 +78,6 @@ async fn test_correct_keyset() {
     assert_ne!(keyset_info.id, old_keyset_info.id);
 
     mint.rotate_keyset(CurrencyUnit::Sat, 32, 0).await.unwrap();
-    let mint = mint_builder.build().await.unwrap();
 
     let active = mint.get_active_keysets();
 

+ 6 - 8
crates/cdk-mint-rpc/src/proto/server.rs

@@ -643,7 +643,7 @@ impl CdkMint for MintRPCServer {
 
         let mint_quote = self
             .mint
-            .localstore
+            .localstore()
             .get_mint_quote(&quote_id)
             .await
             .map_err(|_| Status::invalid_argument("Could not find quote".to_string()))?
@@ -659,9 +659,8 @@ impl CdkMint for MintRPCServer {
                     payment_identifier: mint_quote.request_lookup_id.clone(),
                 };
 
-                let mut tx = self
-                    .mint
-                    .localstore
+                let localstore = self.mint.localstore();
+                let mut tx = localstore
                     .begin_transaction()
                     .await
                     .map_err(|_| Status::internal("Could not start db transaction".to_string()))?;
@@ -693,9 +692,8 @@ impl CdkMint for MintRPCServer {
                     vec![],                               // payment_ids
                 );
 
-                let mut tx = self
-                    .mint
-                    .localstore
+                let mint_store = self.mint.localstore();
+                let mut tx = mint_store
                     .begin_transaction()
                     .await
                     .map_err(|_| Status::internal("Could not update quote".to_string()))?;
@@ -710,7 +708,7 @@ impl CdkMint for MintRPCServer {
 
         let mint_quote = self
             .mint
-            .localstore
+            .localstore()
             .get_mint_quote(&quote_id)
             .await
             .map_err(|_| Status::invalid_argument("Could not find quote".to_string()))?

+ 58 - 59
crates/cdk-mintd/src/main.rs

@@ -19,7 +19,7 @@ use bip39::Mnemonic;
 use cdk::cdk_database::{self, MintDatabase, MintKeysDatabase};
 use cdk::cdk_payment;
 use cdk::cdk_payment::MintPayment;
-use cdk::mint::{MintBuilder, MintMeltLimits};
+use cdk::mint::{Mint, MintBuilder, MintMeltLimits};
 #[cfg(any(
     feature = "cln",
     feature = "lnbits",
@@ -84,16 +84,13 @@ compile_error!(
 async fn main() -> Result<()> {
     let (work_dir, settings, localstore, keystore) = initial_setup().await?;
 
-    let mint_builder = MintBuilder::new()
-        .with_localstore(localstore)
-        .with_keystore(keystore);
+    let mint_builder = MintBuilder::new(localstore);
 
     let (mint_builder, ln_routers) = configure_mint_builder(&settings, mint_builder).await?;
     #[cfg(feature = "auth")]
     let mint_builder = setup_authentication(&settings, &work_dir, mint_builder).await?;
-    let mint_builder_info = mint_builder.mint_info.clone();
 
-    let mint = mint_builder.build().await?;
+    let mint = build_mint(&settings, keystore, mint_builder).await?;
 
     tracing::debug!("Mint built from builder.");
 
@@ -109,7 +106,7 @@ async fn main() -> Result<()> {
         &settings,
         ln_routers,
         &work_dir,
-        mint_builder_info,
+        mint.mint_info().await?,
     )
     .await?;
 
@@ -236,9 +233,6 @@ async fn configure_mint_builder(
     // Configure lightning backend
     let mint_builder = configure_lightning_backend(settings, mint_builder, &mut ln_routers).await?;
 
-    // Configure signatory or seed
-    let mint_builder = configure_signing_method(settings, mint_builder).await?;
-
     // Configure caching
     let mint_builder = configure_cache(settings, mint_builder);
 
@@ -274,7 +268,7 @@ fn configure_basic_info(settings: &config::Settings, mint_builder: MintBuilder)
     }
 
     for contact in contacts {
-        builder = builder.add_contact_info(contact);
+        builder = builder.with_contact_info(contact);
     }
 
     if let Some(pubkey) = settings.mint_info.pubkey {
@@ -435,8 +429,8 @@ async fn configure_backend_for_unit(
 
     if let Some(bolt12) = payment_settings.get("bolt12") {
         if bolt12.as_bool().unwrap_or_default() {
-            mint_builder = mint_builder
-                .add_ln_backend(
+            mint_builder
+                .add_payment_processor(
                     unit.clone(),
                     PaymentMethod::Bolt12,
                     mint_melt_limits,
@@ -446,8 +440,8 @@ async fn configure_backend_for_unit(
         }
     }
 
-    mint_builder = mint_builder
-        .add_ln_backend(
+    mint_builder
+        .add_payment_processor(
             unit.clone(),
             PaymentMethod::Bolt11,
             mint_melt_limits,
@@ -456,47 +450,15 @@ async fn configure_backend_for_unit(
         .await?;
 
     if let Some(input_fee) = settings.info.input_fee_ppk {
-        mint_builder = mint_builder.set_unit_fee(&unit, input_fee)?;
+        mint_builder.set_unit_fee(&unit, input_fee)?;
     }
 
     let nut17_supported = SupportedMethods::default_bolt11(unit);
-    mint_builder = mint_builder.add_supported_websockets(nut17_supported);
+    mint_builder = mint_builder.with_supported_websockets(nut17_supported);
 
     Ok(mint_builder)
 }
 
-/// Configures the signing method (remote signatory or local seed)
-async fn configure_signing_method(
-    settings: &config::Settings,
-    mint_builder: MintBuilder,
-) -> Result<MintBuilder> {
-    if let Some(signatory_url) = settings.info.signatory_url.clone() {
-        tracing::info!(
-            "Connecting to remote signatory to {} with certs {:?}",
-            signatory_url,
-            settings.info.signatory_certs.clone()
-        );
-
-        Ok(mint_builder.with_signatory(Arc::new(
-            cdk_signatory::SignatoryRpcClient::new(
-                signatory_url,
-                settings.info.signatory_certs.clone(),
-            )
-            .await?,
-        )))
-    } else if let Some(mnemonic) = settings
-        .info
-        .mnemonic
-        .clone()
-        .map(|s| Mnemonic::from_str(&s))
-        .transpose()?
-    {
-        Ok(mint_builder.with_seed(mnemonic.to_seed_normalized("").to_vec()))
-    } else {
-        bail!("No seed nor remote signatory set");
-    }
-}
-
 /// Configures cache settings
 fn configure_cache(settings: &config::Settings, mint_builder: MintBuilder) -> MintBuilder {
     let cached_endpoints = vec![
@@ -506,7 +468,7 @@ fn configure_cache(settings: &config::Settings, mint_builder: MintBuilder) -> Mi
     ];
 
     let cache: HttpCache = settings.info.http_cache.clone().into();
-    mint_builder.add_cache(Some(cache.ttl.as_secs()), cached_endpoints)
+    mint_builder.with_cache(Some(cache.ttl.as_secs()), cached_endpoints)
 }
 
 #[cfg(feature = "auth")]
@@ -532,16 +494,9 @@ async fn setup_authentication(
             }
         };
 
-        mint_builder = mint_builder.with_auth_localstore(auth_localstore.clone());
-
         let mint_blind_auth_endpoint =
             ProtectedEndpoint::new(Method::Post, RoutePath::MintBlindAuth);
 
-        mint_builder = mint_builder.set_clear_auth_settings(
-            auth_settings.openid_discovery,
-            auth_settings.openid_client_id,
-        );
-
         let mut protected_endpoints = HashMap::new();
 
         protected_endpoints.insert(mint_blind_auth_endpoint, AuthRequired::Clear);
@@ -644,7 +599,14 @@ async fn setup_authentication(
             }
         }
 
-        mint_builder = mint_builder.set_blind_auth_settings(auth_settings.mint_max_bat);
+        mint_builder = mint_builder.with_auth(
+            auth_localstore.clone(),
+            auth_settings.openid_discovery,
+            auth_settings.openid_client_id,
+            vec![mint_blind_auth_endpoint],
+        );
+        mint_builder =
+            mint_builder.with_blind_auth(auth_settings.mint_max_bat, blind_auth_endpoints);
 
         let mut tx = auth_localstore.begin_transaction().await?;
 
@@ -655,6 +617,43 @@ async fn setup_authentication(
     Ok(mint_builder)
 }
 
+/// Build mints with the configured the signing method (remote signatory or local seed)
+async fn build_mint(
+    settings: &config::Settings,
+    keystore: Arc<dyn MintKeysDatabase<Err = cdk_database::Error> + Send + Sync>,
+    mint_builder: MintBuilder,
+) -> Result<Mint> {
+    if let Some(signatory_url) = settings.info.signatory_url.clone() {
+        tracing::info!(
+            "Connecting to remote signatory to {} with certs {:?}",
+            signatory_url,
+            settings.info.signatory_certs.clone()
+        );
+
+        Ok(mint_builder
+            .build_with_signatory(Arc::new(
+                cdk_signatory::SignatoryRpcClient::new(
+                    signatory_url,
+                    settings.info.signatory_certs.clone(),
+                )
+                .await?,
+            ))
+            .await?)
+    } else if let Some(mnemonic) = settings
+        .info
+        .mnemonic
+        .clone()
+        .map(|s| Mnemonic::from_str(&s))
+        .transpose()?
+    {
+        Ok(mint_builder
+            .build_with_seed(keystore, &mnemonic.to_seed_normalized(""))
+            .await?)
+    } else {
+        bail!("No seed nor remote signatory set");
+    }
+}
+
 async fn start_services(
     mint: Arc<cdk::mint::Mint>,
     settings: &config::Settings,
@@ -704,7 +703,7 @@ async fn start_services(
             mint.set_mint_info(mint_builder_info).await?;
             mint.set_quote_ttl(QuoteTTL::new(10_000, 10_000)).await?;
         } else {
-            if mint.localstore.get_quote_ttl().await.is_err() {
+            if mint.localstore().get_quote_ttl().await.is_err() {
                 mint.set_quote_ttl(QuoteTTL::new(10_000, 10_000)).await?;
             }
             // Add version information

+ 1 - 1
crates/cdk/examples/auth_wallet.rs

@@ -112,7 +112,7 @@ async fn get_access_token(mint_info: &MintInfo) -> String {
         .expect("Nut21 defined")
         .openid_discovery;
 
-    let oidc_client = OidcClient::new(openid_discovery);
+    let oidc_client = OidcClient::new(openid_discovery, None);
 
     // Get the token endpoint from the OIDC configuration
     let token_url = oidc_client

+ 147 - 201
crates/cdk/src/mint/builder.rs

@@ -3,13 +3,13 @@
 use std::collections::HashMap;
 use std::sync::Arc;
 
-use anyhow::anyhow;
 use bitcoin::bip32::DerivationPath;
 use cdk_common::database::{self, MintDatabase, MintKeysDatabase};
 use cdk_common::error::Error;
 use cdk_common::nut04::MintMethodOptions;
 use cdk_common::nut05::MeltMethodOptions;
 use cdk_common::payment::Bolt11Settings;
+#[cfg(feature = "auth")]
 use cdk_common::{nut21, nut22};
 use cdk_signatory::signatory::Signatory;
 
@@ -19,103 +19,91 @@ use super::nut19::{self, CachedEndpoint};
 use super::MintAuthDatabase;
 use super::Nuts;
 use crate::amount::Amount;
-#[cfg(feature = "auth")]
 use crate::cdk_database;
 use crate::cdk_payment::{self, MintPayment};
 use crate::mint::Mint;
+#[cfg(feature = "auth")]
+use crate::nuts::ProtectedEndpoint;
 use crate::nuts::{
     ContactInfo, CurrencyUnit, MeltMethodSettings, MintInfo, MintMethodSettings, MintVersion,
     MppMethodSettings, PaymentMethod,
 };
 use crate::types::PaymentProcessorKey;
 
-/// Cashu Mint
-#[derive(Default)]
+/// Cashu Mint Builder
 pub struct MintBuilder {
-    /// Mint Info
-    pub mint_info: MintInfo,
-    /// Mint Storage backend
-    pub localstore: Option<Arc<dyn MintDatabase<database::Error> + Send + Sync>>,
-    /// Database for the Signatory
-    keystore: Option<Arc<dyn MintKeysDatabase<Err = database::Error> + Send + Sync>>,
-    /// Mint Storage backend
+    mint_info: MintInfo,
+    localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
     #[cfg(feature = "auth")]
     auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>>,
-    /// Ln backends for mint
-    ln: Option<
+    payment_processors:
         HashMap<PaymentProcessorKey, Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>>,
-    >,
-    seed: Option<Vec<u8>>,
     supported_units: HashMap<CurrencyUnit, (u64, u8)>,
     custom_paths: HashMap<CurrencyUnit, DerivationPath>,
-    // protected_endpoints: HashMap<ProtectedEndpoint, AuthRequired>,
-    openid_discovery: Option<String>,
-    signatory: Option<Arc<dyn Signatory + Sync + Send + 'static>>,
 }
 
 impl MintBuilder {
-    /// New mint builder
-    pub fn new() -> MintBuilder {
-        let mut builder = MintBuilder::default();
-
-        let nuts = Nuts::new()
-            .nut07(true)
-            .nut08(true)
-            .nut09(true)
-            .nut10(true)
-            .nut11(true)
-            .nut12(true)
-            .nut14(true)
-            .nut20(true);
-
-        builder.mint_info.nuts = nuts;
-
-        builder
-    }
-
-    /// Set signatory service
-    pub fn with_signatory(mut self, signatory: Arc<dyn Signatory + Sync + Send + 'static>) -> Self {
-        self.signatory = Some(signatory);
-        self
-    }
-
-    /// Set seed
-    pub fn with_seed(mut self, seed: Vec<u8>) -> Self {
-        self.seed = Some(seed);
-        self
-    }
+    /// New [`MintBuilder`]
+    pub fn new(localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>) -> MintBuilder {
+        let mint_info = MintInfo {
+            nuts: Nuts::new()
+                .nut07(true)
+                .nut08(true)
+                .nut09(true)
+                .nut10(true)
+                .nut11(true)
+                .nut12(true),
+            ..Default::default()
+        };
 
-    /// Set localstore
-    pub fn with_localstore(
-        mut self,
-        localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
-    ) -> MintBuilder {
-        self.localstore = Some(localstore);
-        self
+        MintBuilder {
+            mint_info,
+            localstore,
+            #[cfg(feature = "auth")]
+            auth_localstore: None,
+            payment_processors: HashMap::new(),
+            supported_units: HashMap::new(),
+            custom_paths: HashMap::new(),
+        }
     }
 
-    /// Set keystore database
-    pub fn with_keystore(
+    /// Set clear auth settings
+    #[cfg(feature = "auth")]
+    pub fn with_auth(
         mut self,
-        keystore: Arc<dyn MintKeysDatabase<Err = database::Error> + Send + Sync>,
-    ) -> MintBuilder {
-        self.keystore = Some(keystore);
+        auth_localstore: Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>,
+        openid_discovery: String,
+        client_id: String,
+        protected_endpoints: Vec<ProtectedEndpoint>,
+    ) -> Self {
+        self.auth_localstore = Some(auth_localstore);
+        self.mint_info.nuts.nut21 = Some(nut21::Settings::new(
+            openid_discovery,
+            client_id,
+            protected_endpoints,
+        ));
         self
     }
 
-    /// Set auth localstore
+    /// Set blind auth settings
     #[cfg(feature = "auth")]
-    pub fn with_auth_localstore(
+    pub fn with_blind_auth(
         mut self,
-        localstore: Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>,
-    ) -> MintBuilder {
-        self.auth_localstore = Some(localstore);
+        bat_max_mint: u64,
+        protected_endpoints: Vec<ProtectedEndpoint>,
+    ) -> Self {
+        let mut nuts = self.mint_info.nuts;
+
+        nuts.nut22 = Some(nut22::Settings::new(bat_max_mint, protected_endpoints));
+
+        self.mint_info.nuts = nuts;
+
         self
     }
 
-    /// Set Openid discovery url
-    pub fn with_openid_discovery(mut self, openid_discovery: String) -> Self {
-        self.openid_discovery = Some(openid_discovery);
+    /// Set mint info
+    pub fn with_mint_info(mut self, mint_info: MintInfo) -> Self {
+        self.mint_info = mint_info;
         self
     }
 
@@ -168,32 +156,68 @@ impl MintBuilder {
     }
 
     /// Set contact info
-    pub fn add_contact_info(mut self, contact_info: ContactInfo) -> Self {
+    pub fn with_contact_info(mut self, contact_info: ContactInfo) -> Self {
         let mut contacts = self.mint_info.contact.clone().unwrap_or_default();
         contacts.push(contact_info);
         self.mint_info.contact = Some(contacts);
         self
     }
 
-    /// Add ln backend
-    pub async fn add_ln_backend(
+    /// Set pubkey
+    pub fn with_pubkey(mut self, pubkey: crate::nuts::PublicKey) -> Self {
+        self.mint_info.pubkey = Some(pubkey);
+
+        self
+    }
+
+    /// Support websockets
+    pub fn with_supported_websockets(mut self, supported_method: SupportedMethods) -> Self {
+        let mut supported_settings = self.mint_info.nuts.nut17.supported.clone();
+
+        if !supported_settings.contains(&supported_method) {
+            supported_settings.push(supported_method);
+
+            self.mint_info.nuts = self.mint_info.nuts.nut17(supported_settings);
+        }
+
+        self
+    }
+
+    /// Add support for NUT19
+    pub fn with_cache(mut self, ttl: Option<u64>, cached_endpoints: Vec<CachedEndpoint>) -> Self {
+        let nut19_settings = nut19::Settings {
+            ttl,
+            cached_endpoints,
+        };
+
+        self.mint_info.nuts.nut19 = nut19_settings;
+
+        self
+    }
+
+    /// Set custom derivation paths for mint units
+    pub fn with_custom_derivation_paths(
         mut self,
+        custom_paths: HashMap<CurrencyUnit, DerivationPath>,
+    ) -> Self {
+        self.custom_paths = custom_paths;
+        self
+    }
+
+    /// Add payment processor
+    pub async fn add_payment_processor(
+        &mut self,
         unit: CurrencyUnit,
         method: PaymentMethod,
         limits: MintMeltLimits,
-        ln_backend: Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
-    ) -> Result<Self, Error> {
-        let ln_key = PaymentProcessorKey {
+        payment_processor: Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
+    ) -> Result<(), Error> {
+        let key = PaymentProcessorKey {
             unit: unit.clone(),
             method: method.clone(),
         };
 
-        tracing::debug!("Adding ln backed for {}, {}", unit, method);
-        tracing::debug!("with limits {:?}", limits);
-
-        let mut ln = self.ln.unwrap_or_default();
-
-        let settings = ln_backend.get_settings().await?;
+        let settings = payment_processor.get_settings().await?;
 
         let settings: Bolt11Settings = settings.try_into()?;
 
@@ -235,91 +259,19 @@ impl MintBuilder {
         self.mint_info.nuts.nut05.methods.push(melt_method_settings);
         self.mint_info.nuts.nut05.disabled = false;
 
-        ln.insert(ln_key.clone(), ln_backend);
-
         let mut supported_units = self.supported_units.clone();
 
-        supported_units.insert(ln_key.unit, (0, 32));
+        supported_units.insert(key.unit.clone(), (0, 32));
         self.supported_units = supported_units;
 
-        self.ln = Some(ln);
-
-        Ok(self)
-    }
-
-    /// Set pubkey
-    pub fn with_pubkey(mut self, pubkey: crate::nuts::PublicKey) -> Self {
-        self.mint_info.pubkey = Some(pubkey);
-
-        self
-    }
-
-    /// Support websockets
-    pub fn add_supported_websockets(mut self, supported_method: SupportedMethods) -> Self {
-        let mut supported_settings = self.mint_info.nuts.nut17.supported.clone();
-
-        if !supported_settings.contains(&supported_method) {
-            supported_settings.push(supported_method);
-
-            self.mint_info.nuts = self.mint_info.nuts.nut17(supported_settings);
-        }
-
-        self
-    }
-
-    /// Add support for NUT19
-    pub fn add_cache(mut self, ttl: Option<u64>, cached_endpoints: Vec<CachedEndpoint>) -> Self {
-        let nut19_settings = nut19::Settings {
-            ttl,
-            cached_endpoints,
-        };
-
-        self.mint_info.nuts.nut19 = nut19_settings;
-
-        self
-    }
-
-    /// Set custom derivation paths for mint units
-    pub fn add_custom_derivation_paths(
-        mut self,
-        custom_paths: HashMap<CurrencyUnit, DerivationPath>,
-    ) -> Self {
-        self.custom_paths = custom_paths;
-        self
-    }
-
-    /// Set clear auth settings
-    pub fn set_clear_auth_settings(mut self, openid_discovery: String, client_id: String) -> Self {
-        let mut nuts = self.mint_info.nuts;
-
-        nuts.nut21 = Some(nut21::Settings::new(
-            openid_discovery.clone(),
-            client_id,
-            vec![],
-        ));
-
-        self.openid_discovery = Some(openid_discovery);
-
-        self.mint_info.nuts = nuts;
-
-        self
-    }
-
-    /// Set blind auth settings
-    pub fn set_blind_auth_settings(mut self, bat_max_mint: u64) -> Self {
-        let mut nuts = self.mint_info.nuts;
-
-        nuts.nut22 = Some(nut22::Settings::new(bat_max_mint, vec![]));
-
-        self.mint_info.nuts = nuts;
-
-        self
+        self.payment_processors.insert(key, payment_processor);
+        Ok(())
     }
 
     /// Sets the input fee ppk for a given unit
     ///
     /// The unit **MUST** already have been added with a ln backend
-    pub fn set_unit_fee(mut self, unit: &CurrencyUnit, input_fee_ppk: u64) -> Result<Self, Error> {
+    pub fn set_unit_fee(&mut self, unit: &CurrencyUnit, input_fee_ppk: u64) -> Result<(), Error> {
         let (input_fee, _max_order) = self
             .supported_units
             .get_mut(unit)
@@ -327,59 +279,53 @@ impl MintBuilder {
 
         *input_fee = input_fee_ppk;
 
-        Ok(self)
+        Ok(())
     }
 
-    /// Build mint
-    pub async fn build(&self) -> anyhow::Result<Mint> {
-        let localstore = self
-            .localstore
-            .clone()
-            .ok_or(anyhow!("Localstore not set"))?;
-        let ln = self.ln.clone().ok_or(anyhow!("Ln backends not set"))?;
-
-        let signatory = if let Some(signatory) = self.signatory.as_ref() {
-            signatory.clone()
-        } else {
-            let seed = self.seed.as_ref().ok_or(anyhow!("Mint seed not set"))?;
-            let in_memory_signatory = cdk_signatory::db_signatory::DbSignatory::new(
-                self.keystore.clone().ok_or(anyhow!("keystore not set"))?,
-                seed,
-                self.supported_units.clone(),
-                HashMap::new(),
-            )
-            .await?;
-
-            Arc::new(cdk_signatory::embedded::Service::new(Arc::new(
-                in_memory_signatory,
-            )))
-        };
-
+    /// Build the mint with the provided signatory
+    pub async fn build_with_signatory(
+        self,
+        signatory: Arc<dyn Signatory + Send + Sync>,
+    ) -> Result<Mint, Error> {
         #[cfg(feature = "auth")]
-        if let Some(openid_discovery) = &self.openid_discovery {
-            let auth_localstore = self
-                .auth_localstore
-                .clone()
-                .ok_or(anyhow!("Auth localstore not set"))?;
-
-            return Ok(Mint::new_with_auth(
+        if let Some(auth_localstore) = self.auth_localstore {
+            return Mint::new_with_auth(
+                self.mint_info,
                 signatory,
-                localstore,
+                self.localstore,
                 auth_localstore,
-                ln,
-                openid_discovery.clone(),
+                self.payment_processors,
             )
-            .await?);
-        }
-
-        #[cfg(not(feature = "auth"))]
-        if self.openid_discovery.is_some() {
-            return Err(anyhow!(
-                "OpenID discovery URL provided but auth feature is not enabled"
-            ));
+            .await;
         }
+        Mint::new(
+            self.mint_info,
+            signatory,
+            self.localstore,
+            self.payment_processors,
+        )
+        .await
+    }
 
-        Ok(Mint::new(signatory, localstore, ln).await?)
+    /// Build the mint with the provided keystore and seed
+    pub async fn build_with_seed(
+        self,
+        keystore: Arc<dyn MintKeysDatabase<Err = cdk_database::Error> + Send + Sync>,
+        seed: &[u8],
+    ) -> Result<Mint, Error> {
+        let in_memory_signatory = cdk_signatory::db_signatory::DbSignatory::new(
+            keystore,
+            seed,
+            self.supported_units.clone(),
+            HashMap::new(),
+        )
+        .await?;
+
+        let signatory = Arc::new(cdk_signatory::embedded::Service::new(Arc::new(
+            in_memory_signatory,
+        )));
+
+        self.build_with_signatory(signatory).await
     }
 }
 

+ 1 - 1
crates/cdk/src/mint/ln.rs

@@ -23,7 +23,7 @@ impl Mint {
             return Ok(());
         }
 
-        let ln = match self.ln.get(&PaymentProcessorKey::new(
+        let ln = match self.payment_processors.get(&PaymentProcessorKey::new(
             quote.unit.clone(),
             quote.payment_method.clone(),
         )) {

+ 3 - 3
crates/cdk/src/mint/melt.rs

@@ -152,7 +152,7 @@ impl Mint {
         .await?;
 
         let ln = self
-            .ln
+            .payment_processors
             .get(&PaymentProcessorKey::new(
                 unit.clone(),
                 PaymentMethod::Bolt11,
@@ -250,7 +250,7 @@ impl Mint {
         .await?;
 
         let ln = self
-            .ln
+            .payment_processors
             .get(&PaymentProcessorKey::new(
                 unit.clone(),
                 PaymentMethod::Bolt12,
@@ -586,7 +586,7 @@ impl Mint {
                     _ => None,
                 };
                 tracing::debug!("partial_amount: {:?}", partial_amount);
-                let ln = match self.ln.get(&PaymentProcessorKey::new(
+                let ln = match self.payment_processors.get(&PaymentProcessorKey::new(
                     quote.unit.clone(),
                     PaymentMethod::Bolt11,
                 )) {

+ 58 - 41
crates/cdk/src/mint/mod.rs

@@ -53,17 +53,17 @@ pub struct Mint {
     ///
     /// It is implemented in the cdk-signatory crate, and it can be embedded in the mint or it can
     /// be a gRPC client to a remote signatory server.
-    pub signatory: Arc<dyn Signatory + Send + Sync>,
+    signatory: Arc<dyn Signatory + Send + Sync>,
     /// Mint Storage backend
-    pub localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
+    localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
     /// Auth Storage backend (only available with auth feature)
     #[cfg(feature = "auth")]
-    pub auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>>,
-    /// Ln backends for mint
-    pub ln:
+    auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>>,
+    /// Payment processors for mint
+    payment_processors:
         HashMap<PaymentProcessorKey, Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>>,
     /// Subscription manager
-    pub pubsub_manager: Arc<PubSubManager>,
+    pubsub_manager: Arc<PubSubManager>,
     #[cfg(feature = "auth")]
     oidc_client: Option<OidcClient>,
     /// In-memory keyset
@@ -71,40 +71,23 @@ pub struct Mint {
 }
 
 impl Mint {
-    /// Get the payment processor for the given unit and payment method
-    pub fn get_payment_processor(
-        &self,
-        unit: CurrencyUnit,
-        payment_method: PaymentMethod,
-    ) -> Result<Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>, Error> {
-        let key = PaymentProcessorKey::new(unit.clone(), payment_method.clone());
-        self.ln.get(&key).cloned().ok_or_else(|| {
-            tracing::info!(
-                "No payment processor set for pair {}, {}",
-                unit,
-                payment_method
-            );
-            Error::UnsupportedUnit
-        })
-    }
-
     /// Create new [`Mint`] without authentication
     pub async fn new(
+        mint_info: MintInfo,
         signatory: Arc<dyn Signatory + Send + Sync>,
         localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
-        ln: HashMap<
+        payment_processors: HashMap<
             PaymentProcessorKey,
             Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
         >,
     ) -> Result<Self, Error> {
         Self::new_internal(
+            mint_info,
             signatory,
             localstore,
             #[cfg(feature = "auth")]
             None,
-            ln,
-            #[cfg(feature = "auth")]
-            None,
+            payment_processors,
         )
         .await
     }
@@ -112,21 +95,21 @@ impl Mint {
     /// Create new [`Mint`] with authentication support
     #[cfg(feature = "auth")]
     pub async fn new_with_auth(
+        mint_info: MintInfo,
         signatory: Arc<dyn Signatory + Send + Sync>,
         localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
         auth_localstore: Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>,
-        ln: HashMap<
+        payment_processors: HashMap<
             PaymentProcessorKey,
             Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
         >,
-        open_id_discovery: String,
     ) -> Result<Self, Error> {
         Self::new_internal(
+            mint_info,
             signatory,
             localstore,
             Some(auth_localstore),
-            ln,
-            Some(open_id_discovery),
+            payment_processors,
         )
         .await
     }
@@ -134,21 +117,17 @@ impl Mint {
     /// Internal function to create a new [`Mint`] with shared logic
     #[inline]
     async fn new_internal(
+        mint_info: MintInfo,
         signatory: Arc<dyn Signatory + Send + Sync>,
         localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
         #[cfg(feature = "auth")] auth_localstore: Option<
             Arc<dyn database::MintAuthDatabase<Err = database::Error> + Send + Sync>,
         >,
-        ln: HashMap<
+        payment_processors: HashMap<
             PaymentProcessorKey,
             Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
         >,
-        #[cfg(feature = "auth")] open_id_discovery: Option<String>,
     ) -> Result<Self, Error> {
-        #[cfg(feature = "auth")]
-        let oidc_client =
-            open_id_discovery.map(|openid_discovery| OidcClient::new(openid_discovery.clone()));
-
         let keysets = signatory.keysets().await?;
         if !keysets
             .keysets
@@ -168,19 +147,57 @@ impl Mint {
                 .count()
         );
 
+        let mint_store = localstore.clone();
+        let mut tx = mint_store.begin_transaction().await?;
+        tx.set_mint_info(mint_info.clone()).await?;
+        tx.set_quote_ttl(QuoteTTL::default()).await?;
+        tx.commit().await?;
+
         Ok(Self {
             signatory,
             pubsub_manager: Arc::new(localstore.clone().into()),
             localstore,
             #[cfg(feature = "auth")]
-            oidc_client,
-            ln,
+            oidc_client: mint_info.nuts.nut21.as_ref().map(|nut21| {
+                OidcClient::new(
+                    nut21.openid_discovery.clone(),
+                    Some(nut21.client_id.clone()),
+                )
+            }),
+            payment_processors,
             #[cfg(feature = "auth")]
             auth_localstore,
             keysets: Arc::new(ArcSwap::new(keysets.keysets.into())),
         })
     }
 
+    /// Get the payment processor for the given unit and payment method
+    pub fn get_payment_processor(
+        &self,
+        unit: CurrencyUnit,
+        payment_method: PaymentMethod,
+    ) -> Result<Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>, Error> {
+        let key = PaymentProcessorKey::new(unit.clone(), payment_method.clone());
+        self.payment_processors.get(&key).cloned().ok_or_else(|| {
+            tracing::info!(
+                "No payment processor set for pair {}, {}",
+                unit,
+                payment_method
+            );
+            Error::UnsupportedUnit
+        })
+    }
+
+    /// Localstore
+    pub fn localstore(&self) -> Arc<dyn MintDatabase<database::Error> + Send + Sync> {
+        Arc::clone(&self.localstore)
+    }
+
+    /// Pub Sub manager
+    pub fn pubsub_manager(&self) -> Arc<PubSubManager> {
+        Arc::clone(&self.pubsub_manager)
+    }
+
     /// Get mint info
     #[instrument(skip_all)]
     pub async fn mint_info(&self) -> Result<MintInfo, Error> {
@@ -259,7 +276,7 @@ impl Mint {
             Vec<PaymentProcessorKey>,
         )> = Vec::new();
 
-        for (key, ln) in self.ln.iter() {
+        for (key, ln) in self.payment_processors.iter() {
             // Check if we already have this processor
             let found = processor_groups.iter_mut().find(|(proc_ref, _)| {
                 // Compare Arc pointer equality using ptr_eq
@@ -609,7 +626,7 @@ mod tests {
             .expect("Failed to create signatory"),
         );
 
-        Mint::new(signatory, localstore, HashMap::new())
+        Mint::new(MintInfo::default(), signatory, localstore, HashMap::new())
             .await
             .unwrap()
     }

+ 1 - 1
crates/cdk/src/mint/start_up_check.rs

@@ -27,7 +27,7 @@ impl Mint {
                 method: PaymentMethod::Bolt11,
             };
 
-            let ln_backend = match self.ln.get(&ln_key) {
+            let ln_backend = match self.payment_processors.get(&ln_key) {
                 Some(ln_backend) => ln_backend,
                 None => {
                     tracing::warn!("No backend for ln key: {:?}", ln_key);

+ 40 - 9
crates/cdk/src/oidc_client.rs

@@ -32,9 +32,9 @@ pub enum Error {
     /// Unsupported Algo
     #[error("Unsupported signing algo")]
     UnsupportedSigningAlgo,
-    /// Access token not returned
-    #[error("Error getting access token")]
-    AccessTokenMissing,
+    /// Invalid Client ID
+    #[error("Invalid Client ID")]
+    InvalidClientId,
 }
 
 impl From<Error> for cdk_common::error::Error {
@@ -58,6 +58,7 @@ pub struct OidcConfig {
 pub struct OidcClient {
     client: Client,
     openid_discovery: String,
+    client_id: Option<String>,
     oidc_config: Arc<RwLock<Option<OidcConfig>>>,
     jwks_set: Arc<RwLock<Option<JwkSet>>>,
 }
@@ -88,10 +89,11 @@ pub struct TokenResponse {
 
 impl OidcClient {
     /// Create new [`OidcClient`]
-    pub fn new(openid_discovery: String) -> Self {
+    pub fn new(openid_discovery: String, client_id: Option<String>) -> Self {
         Self {
             client: Client::new(),
             openid_discovery,
+            client_id,
             oidc_config: Arc::new(RwLock::new(None)),
             jwks_set: Arc::new(RwLock::new(None)),
         }
@@ -192,11 +194,40 @@ impl OidcClient {
             validation
         };
 
-        if let Err(err) =
-            decode::<HashMap<String, serde_json::Value>>(cat_jwt, &decoding_key, &validation)
-        {
-            tracing::debug!("Could not verify cat: {}", err);
-            return Err(err.into());
+        match decode::<HashMap<String, serde_json::Value>>(cat_jwt, &decoding_key, &validation) {
+            Ok(claims) => {
+                tracing::debug!("Successfully verified cat");
+                tracing::debug!("Claims: {:?}", claims.claims);
+                if let Some(client_id) = &self.client_id {
+                    if let Some(token_client_id) = claims.claims.get("client_id") {
+                        if let Some(token_client_id_value) = token_client_id.as_str() {
+                            if token_client_id_value != client_id {
+                                tracing::warn!(
+                                    "Client ID mismatch: expected {}, got {}",
+                                    client_id,
+                                    token_client_id_value
+                                );
+                                return Err(Error::InvalidClientId);
+                            }
+                        }
+                    } else if let Some(azp) = claims.claims.get("azp") {
+                        if let Some(azp_value) = azp.as_str() {
+                            if azp_value != client_id {
+                                tracing::warn!(
+                                    "Client ID (azp) mismatch: expected {}, got {}",
+                                    client_id,
+                                    azp_value
+                                );
+                                return Err(Error::InvalidClientId);
+                            }
+                        }
+                    }
+                }
+            }
+            Err(err) => {
+                tracing::debug!("Could not verify cat: {}", err);
+                return Err(err.into());
+            }
         }
 
         Ok(())

+ 6 - 3
crates/cdk/src/wallet/mod.rs

@@ -268,8 +268,9 @@ impl Wallet {
                                 auth_wallet.protected_endpoints.write().await;
                             *protected_endpoints = mint_info.protected_endpoints();
 
-                            if let Some(oidc_client) =
-                                mint_info.openid_discovery().map(OidcClient::new)
+                            if let Some(oidc_client) = mint_info
+                                .openid_discovery()
+                                .map(|url| OidcClient::new(url, None))
                             {
                                 auth_wallet.set_oidc_client(Some(oidc_client)).await;
                             }
@@ -277,7 +278,9 @@ impl Wallet {
                         None => {
                             tracing::info!("Mint has auth enabled creating auth wallet");
 
-                            let oidc_client = mint_info.openid_discovery().map(OidcClient::new);
+                            let oidc_client = mint_info
+                                .openid_discovery()
+                                .map(|url| OidcClient::new(url, None));
                             let new_auth_wallet = AuthWallet::new(
                                 self.mint_url.clone(),
                                 None,