From 9a1036f2c7a3423d008710208b43a25fa81ea130 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 7 Jan 2026 19:47:10 +0000 Subject: [PATCH 1/4] Refactor: Infer OIDC URL scheme dynamically This change dynamically determines whether to use HTTP or HTTPS for OIDC URLs based on the app host, improving flexibility and security. Co-authored-by: contact --- src/webserver/oidc.rs | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index a1bec14b..c897372f 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -478,6 +478,16 @@ fn parse_logout_params(query: &str) -> anyhow::Result { .map(Query::into_inner) } +fn infer_url_scheme(app_host: &str) -> &'static str { + let Ok(url) = Url::parse(&format!("https://{app_host}")) else { + return "http"; + }; + match url.host() { + Some(openidconnect::url::Host::Domain(domain)) if domain != "localhost" => "https", + _ => "http", + } +} + async fn process_oidc_logout( oidc_state: &OidcState, request: &ServiceRequest, @@ -494,11 +504,11 @@ async fn process_oidc_logout( .ok() .flatten(); - let scheme = request.connection_info().scheme().to_string(); + let scheme = infer_url_scheme(&oidc_state.config.app_host); let mut response = if let Some(end_session_endpoint) = oidc_state.get_end_session_endpoint().await { let absolute_redirect_uri = - build_absolute_uri(&oidc_state.config.app_host, ¶ms.redirect_uri, &scheme)?; + build_absolute_uri(&oidc_state.config.app_host, ¶ms.redirect_uri, scheme)?; let post_logout_redirect_uri = PostLogoutRedirectUrl::new(absolute_redirect_uri.clone()).with_context(|| { format!("Invalid post_logout_redirect_uri: {absolute_redirect_uri}") @@ -884,9 +894,10 @@ fn make_oidc_client( let client_id = openidconnect::ClientId::new(config.client_id.clone()); let client_secret = openidconnect::ClientSecret::new(config.client_secret.clone()); - let mut redirect_url = RedirectUrl::new(format!( - "https://{}{}", - config.app_host, SQLPAGE_REDIRECT_URI, + let scheme = infer_url_scheme(&config.app_host); + let redirect_url = RedirectUrl::new(format!( + "{}://{}{}", + scheme, config.app_host, SQLPAGE_REDIRECT_URI, )) .with_context(|| { format!( @@ -894,18 +905,6 @@ fn make_oidc_client( config.app_host ) })?; - let needs_http = match redirect_url.url().host() { - Some(openidconnect::url::Host::Domain(domain)) => domain == "localhost", - Some(openidconnect::url::Host::Ipv4(_) | openidconnect::url::Host::Ipv6(_)) => true, - None => false, - }; - if needs_http { - log::debug!("App host seems to be local, changing redirect URL to HTTP"); - redirect_url = RedirectUrl::new(format!( - "http://{}{}", - config.app_host, SQLPAGE_REDIRECT_URI, - ))?; - } log::info!("OIDC redirect URL for {}: {redirect_url}", config.client_id); let client = OidcClient::from_provider_metadata(provider_metadata, client_id, Some(client_secret)) From fca28673ae9f4381428dc3e94e2483d9a9ee3b53 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 8 Jan 2026 11:04:35 +0000 Subject: [PATCH 2/4] Refactor OIDC URL handling to use X-Forwarded-Proto header Co-authored-by: contact --- src/webserver/oidc.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index c897372f..33c96ab1 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -478,16 +478,6 @@ fn parse_logout_params(query: &str) -> anyhow::Result { .map(Query::into_inner) } -fn infer_url_scheme(app_host: &str) -> &'static str { - let Ok(url) = Url::parse(&format!("https://{app_host}")) else { - return "http"; - }; - match url.host() { - Some(openidconnect::url::Host::Domain(domain)) if domain != "localhost" => "https", - _ => "http", - } -} - async fn process_oidc_logout( oidc_state: &OidcState, request: &ServiceRequest, @@ -504,7 +494,12 @@ async fn process_oidc_logout( .ok() .flatten(); - let scheme = infer_url_scheme(&oidc_state.config.app_host); + let scheme = request + .headers() + .get("x-forwarded-proto") + .and_then(|h| h.to_str().ok()) + .map(|s| s.split(',').next().unwrap_or(s).trim().to_string()) + .unwrap_or_else(|| request.connection_info().scheme().to_string()); let mut response = if let Some(end_session_endpoint) = oidc_state.get_end_session_endpoint().await { let absolute_redirect_uri = @@ -894,10 +889,9 @@ fn make_oidc_client( let client_id = openidconnect::ClientId::new(config.client_id.clone()); let client_secret = openidconnect::ClientSecret::new(config.client_secret.clone()); - let scheme = infer_url_scheme(&config.app_host); - let redirect_url = RedirectUrl::new(format!( - "{}://{}{}", - scheme, config.app_host, SQLPAGE_REDIRECT_URI, + let mut redirect_url = RedirectUrl::new(format!( + "https://{}{}", + config.app_host, SQLPAGE_REDIRECT_URI, )) .with_context(|| { format!( @@ -905,6 +899,18 @@ fn make_oidc_client( config.app_host ) })?; + let needs_http = match redirect_url.url().host() { + Some(openidconnect::url::Host::Domain(domain)) => domain == "localhost", + Some(openidconnect::url::Host::Ipv4(_) | openidconnect::url::Host::Ipv6(_)) => true, + None => false, + }; + if needs_http { + log::debug!("App host seems to be local, changing redirect URL to HTTP"); + redirect_url = RedirectUrl::new(format!( + "http://{}{}", + config.app_host, SQLPAGE_REDIRECT_URI, + ))?; + } log::info!("OIDC redirect URL for {}: {redirect_url}", config.client_id); let client = OidcClient::from_provider_metadata(provider_metadata, client_id, Some(client_secret)) From 83b4a0bb1297ac92e3ce2215b209f15dcd1c72a9 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 8 Jan 2026 11:14:59 +0000 Subject: [PATCH 3/4] Fix: Pass scheme as reference in build_absolute_uri Co-authored-by: contact --- src/webserver/oidc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index 33c96ab1..baa9928b 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -503,7 +503,7 @@ async fn process_oidc_logout( let mut response = if let Some(end_session_endpoint) = oidc_state.get_end_session_endpoint().await { let absolute_redirect_uri = - build_absolute_uri(&oidc_state.config.app_host, ¶ms.redirect_uri, scheme)?; + build_absolute_uri(&oidc_state.config.app_host, ¶ms.redirect_uri, &scheme)?; let post_logout_redirect_uri = PostLogoutRedirectUrl::new(absolute_redirect_uri.clone()).with_context(|| { format!("Invalid post_logout_redirect_uri: {absolute_redirect_uri}") From ded3e38f28d2225c469fd937841c2beb97b46592 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 8 Jan 2026 12:54:05 +0000 Subject: [PATCH 4/4] Refactor: Extract get_request_scheme helper function Co-authored-by: contact --- src/webserver/oidc.rs | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index baa9928b..3d17bbf2 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -478,6 +478,16 @@ fn parse_logout_params(query: &str) -> anyhow::Result { .map(Query::into_inner) } +fn get_request_scheme(request: &ServiceRequest) -> String { + request + .headers() + .get("x-forwarded-proto") + .and_then(|h| h.to_str().ok()) + .and_then(|s| s.split(',').next()) + .map(|s| s.trim().to_string()) + .unwrap_or_else(|| request.connection_info().scheme().to_string()) +} + async fn process_oidc_logout( oidc_state: &OidcState, request: &ServiceRequest, @@ -494,12 +504,7 @@ async fn process_oidc_logout( .ok() .flatten(); - let scheme = request - .headers() - .get("x-forwarded-proto") - .and_then(|h| h.to_str().ok()) - .map(|s| s.split(',').next().unwrap_or(s).trim().to_string()) - .unwrap_or_else(|| request.connection_info().scheme().to_string()); + let scheme = get_request_scheme(request); let mut response = if let Some(end_session_endpoint) = oidc_state.get_end_session_endpoint().await { let absolute_redirect_uri = @@ -1109,6 +1114,23 @@ mod tests { assert_eq!(location, "/foo"); } + #[test] + fn test_get_request_scheme() { + use actix_web::test::TestRequest; + let req = TestRequest::default().to_srv_request(); + assert_eq!(get_request_scheme(&req), "http"); + + let req = TestRequest::default() + .insert_header(("x-forwarded-proto", "https")) + .to_srv_request(); + assert_eq!(get_request_scheme(&req), "https"); + + let req = TestRequest::default() + .insert_header(("x-forwarded-proto", "https, http")) + .to_srv_request(); + assert_eq!(get_request_scheme(&req), "https"); + } + #[test] fn parse_auth0_rfc3339_updated_at() { let claims_json = r#"{