{"record":{"id":"d17e6e709e6965f9","repo":"windmill-labs/windmill","slug":"invalid-authorization-endpoint-url-e","errorCode":null,"errorMessage":"Invalid authorization endpoint URL: {e}","messagePattern":"Invalid authorization endpoint URL: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-oauth/src/lib.rs","lineNumber":334,"sourceCode":"\n/// OAuth callback parameters\n#[derive(Deserialize)]\npub struct OAuthCallback {\n    pub code: String,\n    pub state: String,\n}\n\n/// Build a basic OAuth client from configuration\npub fn build_basic_client(\n    name: String,\n    config: OAuthConfig,\n    client_params: OAuthClient,\n    login: bool,\n    base_url: &str,\n    override_callback: Option<String>,\n) -> error::Result<(String, OClient)> {\n    let auth_url = Url::parse(&config.auth_url)\n        .map_err(|e| anyhow!(\"Invalid authorization endpoint URL: {e}\"))?;\n    let token_url =\n        Url::parse(&config.token_url).map_err(|e| anyhow!(\"Invalid token endpoint URL: {e}\"))?;\n\n    let redirect_url = if login {\n        format!(\"{base_url}/user/login_callback/{name}\")\n    } else if let Some(callback) = override_callback {\n        callback\n    } else {\n        format!(\"{base_url}/oauth/callback/{name}\")\n    };\n\n    let mut client = OClient::new(client_params.id, auth_url, token_url);\n    if config.req_body_auth.unwrap_or(false) {\n        client.set_auth_type(AuthType::RequestBody);\n    }\n    client.set_client_secret(client_params.secret.clone());\n    client.set_redirect_url(\n        Url::parse(&redirect_url).map_err(|e| anyhow!(\"Invalid redirect URL: {e}\"))?,","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-oauth/src/lib.rs#L316-L352","documentation":"build_basic_client parses the OAuth provider's authorization endpoint URL (config.auth_url) with Url::parse before constructing the oauth2 client. If the stored URL is not a syntactically valid absolute URL, the client cannot be built and an anyhow error wrapping the parse failure is returned.","triggerScenarios":"Calling build_basic_client (directly or via build_client_credentials_oauth_client) with an OAuthClient config whose auth_url is empty, missing a scheme (e.g. 'github.com/login/oauth/authorize'), contains spaces, or is otherwise not parseable as an absolute URL.","commonSituations":"Admins entering an SSO/OAuth provider config in instance settings paste only the host or path without 'https://'; a trailing typo or whitespace; a migration or environment variable that injects an empty AUTH_URL; provider documentation changes the endpoint shape.","solutions":["Fix the auth_url in the OAuth/SSO configuration so it is a full absolute URL including scheme, e.g. https://github.com/login/oauth/authorize","Check for hidden whitespace, newlines, or placeholder text in the configured value","If the value comes from an environment variable or DB column, verify it is actually populated (an empty string fails Url::parse)","Validate with a quick test: Url::parse(value) in Rust or new URL(value) in JS to see the exact parse error embedded in the message"],"exampleFix":"// before\nauth_url = \"github.com/login/oauth/authorize\"\n// after\nauth_url = \"https://github.com/login/oauth/authorize\"","handlingStrategy":"validation","validationCode":"fn valid_auth_url(s: &str) -> bool { Url::parse(s).map(|u| u.scheme().starts_with(\"http\")).unwrap_or(false) }\nassert!(valid_auth_url(\"https://github.com/login/oauth/authorize\"));","typeGuard":"fn is_absolute_http_url(s: &str) -> bool {\n    Url::parse(s).map(|u| matches!(u.scheme(), \"http\" | \"https\") && !u.cannot_be_a_base()).unwrap_or(false)\n}","tryCatchPattern":"match build_basic_client(&config, login, base_url, None) {\n    Ok((name, client)) => client,\n    Err(e) if e.to_string().contains(\"Invalid authorization endpoint URL\") => {\n        // fix config.auth_url before retrying\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always store full absolute URLs (with https://) in OAuth provider configs","Trim whitespace from config values before saving","Add a config-validation step at provider save time using Url::parse"],"tags":["oauth","url-parsing","configuration"],"backgroundTag":"invalid-url-format","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}