cts-common 0.36.0

Common types and traits used across the CipherStash ecosystem
Documentation
use url::Url;

/// Build the JWKS endpoint URL for an OIDC issuer.
///
/// Normalises the issuer's trailing slash before joining so the full issuer
/// path is preserved. Without this, `Url::join` replaces the last path
/// segment — e.g. `https://foo.com/auth/v1` would produce
/// `https://foo.com/auth/.well-known/jwks.json`, silently dropping `v1`.
pub fn jwks_url(issuer: &str) -> Result<Url, url::ParseError> {
    let mut base = issuer.parse::<Url>()?;
    if !base.path().ends_with('/') {
        let new_path = format!("{}/", base.path());
        base.set_path(&new_path);
    }
    base.join(".well-known/jwks.json")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn preserves_full_path_when_issuer_has_trailing_slash() {
        let url = jwks_url("https://foo.com/auth/v1/").unwrap();
        assert_eq!(
            url.as_str(),
            "https://foo.com/auth/v1/.well-known/jwks.json"
        );
    }

    #[test]
    fn preserves_full_path_when_issuer_has_no_trailing_slash() {
        let url = jwks_url("https://foo.com/auth/v1").unwrap();
        assert_eq!(
            url.as_str(),
            "https://foo.com/auth/v1/.well-known/jwks.json"
        );
    }

    #[test]
    fn handles_root_issuer() {
        let url = jwks_url("https://foo.com").unwrap();
        assert_eq!(url.as_str(), "https://foo.com/.well-known/jwks.json");
    }
}