clockworklabs/SpacetimeDB · error · TokenValidationError

Invalid OIDC URL scheme: {url}

Error message

Invalid OIDC URL scheme: {url}

What it means

When building a token validator from an OIDC issuer URL, SpacetimeDB's core validates that the URL scheme is http:// or https:// via validate_url_scheme. Any other scheme (or a missing scheme) is rejected with this TokenValidationError, because OIDC discovery and JWKS fetching require standard HTTP(S) transport.

Source

Thrown at crates/core/src/auth/token_validation.rs:424

        Ok(Self { keys })
    }
}

impl JsonWebKeySet {
    fn key_with_id(&self, kid: &str) -> Option<&JsonWebKey> {
        self.keys.iter().find(|key| key.kid.as_deref() == Some(kid))
    }

    fn keys_without_ids(&self) -> impl Iterator<Item = &JsonWebKey> {
        self.keys.iter().filter(|key| key.kid.is_none())
    }
}

fn validate_url_scheme(url: &str) -> Result<(), TokenValidationError> {
    if url.starts_with("http://") || url.starts_with("https://") {
        Ok(())
    } else {
        Err(TokenValidationError::Other(anyhow::anyhow!(
            "Invalid OIDC URL scheme: {url}"
        )))
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use crate::auth::identity::{IncomingClaims, SpacetimeIdentityClaims};
    use crate::auth::token_validation::{
        BasicTokenValidator, CachingOidcTokenValidator, FullTokenValidator, JwtErrorKind, OidcTokenValidator,
        TokenSigner, TokenValidationError, TokenValidator,
    };
    use crate::auth::JwtKeys;
    use base64::Engine;
    use openssl::ec::{EcGroup, EcKey};
    use serde_json;

View on GitHub (pinned to 3653d2ed49)

Solutions

  1. Prefix the URL with https:// (or http:// only for non-production/local testing)
  2. Trim whitespace and strip hidden characters from the configured URL
  3. Check the config/env value feeding from_oidc_url points at the actual OIDC issuer endpoint
  4. Validate the URL with a parser before passing it into the token validation config

Example fix

// before
let cfg = TokenValidationConfig::from_oidc_url("issuer.example.com")?; // Err: Invalid OIDC URL scheme
// after
let cfg = TokenValidationConfig::from_oidc_url("https://issuer.example.com")?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_https(url: &str) -> Result<&str, String> {
    let trimmed = url.trim();
    if trimmed.starts_with("https://") || trimmed.starts_with("http://") {
        Ok(trimmed)
    } else {
        Err(format!("OIDC URL must start with https:// or http://, got: {url}"))
    }
}

Type guard

fn is_http_url(url: &str) -> bool {
    url.trim_start().starts_with("http://") || url.trim_start().starts_with("https://")
}

Try / catch

let cfg = TokenValidationConfig::from_oidc_url(&url).map_err(|e| {
    eprintln!("OIDC URL validation failed: {e}");
    ConfigError::InvalidOidcUrl(url.clone())
})?;

Prevention

When it happens

Trigger: Calling TokenValidationConfig::from_oidc_url (or related setup) with a URL like "grpc://...", "localhost:8080" (no scheme), "ftp://...", or a URL with leading whitespace so the http(s) prefix check fails.

Common situations: Typing the issuer as a bare host without scheme; copying an internal scheme (e.g. grpc://, unix://) into the OIDC URL field; whitespace or invisible characters before the scheme in environment/config values.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@3653d2ed49 (2026-09-06). Data as JSON: /api/errors/791795c836700a6b. Report an issue: GitHub.