kych

OAuth 2.0 API for Swiyu to enable Taler integration of Swiyu for KYC (experimental)
Log | Files | Refs

commit 93f90f6d4994f4a976b170ecda88d511c3276724
parent eb9f58ce4af8cb2ba25265d698cb68ecd8eaff8e
Author: Henrique Chan Carvalho Machado <henriqueccmachado@tecnico.ulisboa.pt>
Date:   Sun, 19 Oct 2025 22:33:13 +0200

oauth2_gateway: implemented cryptographically secure nonce generation

Diffstat:
Moauth2_gateway/Cargo.toml | 5++++-
Aoauth2_gateway/src/crypto.rs | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Moauth2_gateway/src/handlers.rs | 16+++++++---------
Moauth2_gateway/src/lib.rs | 5+++--
4 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/oauth2_gateway/Cargo.toml b/oauth2_gateway/Cargo.toml @@ -23,7 +23,7 @@ tower-http = { version = "0.6.6", features = ["trace"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.145" -# HTTP client needed for performing requests +# HTTP client reqwest = { version = "0.12", features = ["json"] } # Configuration @@ -41,3 +41,6 @@ tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } # Error handling anyhow = "1.0.100" +# Cryptography +rand = "0.8.5" +base64 = "0.22.1" diff --git a/oauth2_gateway/src/crypto.rs b/oauth2_gateway/src/crypto.rs @@ -0,0 +1,53 @@ +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _}; +use rand::Rng; + +/// Generate a cryptographically secure nonce +/// +/// Format: base64 encoded random bytes +/// Length: 256 bits (43 base64 characters) +/// +/// Example: "k7E9mZqYvXwPxR2nT8uL5sA6fH3jC1dG4bN0iM9oU2p" +pub fn generate_nonce() -> String { + let mut rng = rand::thread_rng(); + let mut bytes = [0u8; 32]; // 32 bytes + rng.fill(&mut bytes); + + // base64 encoding (no padding) + URL_SAFE_NO_PAD.encode(bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashSet; + + #[test] + fn test_nonce_generation() { + let nonce = generate_nonce(); + + // Check length (32 bytes base64 = 43 chars without padding) + assert_eq!(nonce.len(), 43); + + // Check it's URL-safe (only contains valid characters) + assert!(nonce.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_')); + } + + #[test] + fn test_nonces_are_unique() { + let mut nonces = HashSet::new(); + + // Generate 1000 nonces, all should be unique + for _ in 0..1000 { + let nonce = generate_nonce(); + assert!(nonces.insert(nonce), "Duplicate nonce generated!"); + } + } + + #[test] + fn test_no_padding_in_tokens() { + // Ensure no '=' padding characters + let nonce = generate_nonce(); + + assert!(!nonce.contains('=')); + } +} +\ No newline at end of file diff --git a/oauth2_gateway/src/handlers.rs b/oauth2_gateway/src/handlers.rs @@ -9,6 +9,7 @@ use serde_json::json; use crate::{ models::*, state::AppState, + crypto, }; // Health check endpoint @@ -27,10 +28,8 @@ pub async fn setup( Json(request): Json<SetupRequest>, ) -> impl IntoResponse { tracing::info!("Setup request for client: {}, scope: {}", client_id, request.scope); - - // Generate a simple nonce for now - // TODO: Change to cyptographic nonce - let nonce = uuid::Uuid::new_v4().to_string(); + + let nonce = crypto::generate_nonce(); tracing::info!("Generated nonce: {}", nonce); @@ -47,6 +46,7 @@ pub async fn authorize( ) -> impl IntoResponse { tracing::info!("Authorize request for nonce: {}", nonce); + // TODO: Validate nonce // TODO: Call the SwiyuVerifier to generate the QR code/verification URL // For now, return a mock response @@ -73,10 +73,9 @@ pub async fn token( } // TODO: Validate nonce/code - // TODO: Change to cyptographic token + // TODO: Change to cryptographically secure token - // Generate a simple access token - let access_token = uuid::Uuid::new_v4().to_string(); + let access_token = crypto::generate_nonce(); let response = TokenResponse { access_token, @@ -125,8 +124,7 @@ pub async fn notification_webhook( request.verification_complete ); - // TODO: When verification is complete, post the Exchange at - // TODO: {exchange_base_url}/oauth2gw/kyc/notify/{clientId} + // TODO: POST the Exchange at {exchange_base_url}/oauth2gw/kyc/notify/{clientId} StatusCode::OK } diff --git a/oauth2_gateway/src/lib.rs b/oauth2_gateway/src/lib.rs @@ -1,4 +1,5 @@ pub mod config; pub mod handlers; pub mod models; -pub mod state; -\ No newline at end of file +pub mod state; +pub mod crypto; +\ No newline at end of file