jlcodes99/cockpit-tools · error

默认 OAuth client 配置无效

Error message

默认 OAuth client 配置无效

What it means

get_auth_url in crates/cockpit-core/src/modules/oauth.rs:77 builds the Google OAuth authorization URL and calls oauth_client_config(None).expect("默认 OAuth client 配置无效"). The Err path comes from resolve_oauth_client_key, which only fails when a preferred client key that is not the default is supplied. Since get_auth_url passes None, the resolver always returns the default key, so this panic is a defensive guard and is effectively unreachable at runtime unless the code is changed to forward a user-specified client key.

Source

Thrown at crates/cockpit-core/src/modules/oauth.rs:77

        Some(key) if key.is_empty() => Ok(DEFAULT_OAUTH_CLIENT_KEY.to_string()),
        Some(key) => Err(format!(
            "未知 OAuth client: {},当前版本仅支持 {}",
            key, DEFAULT_OAUTH_CLIENT_KEY
        )),
        None => Ok(DEFAULT_OAUTH_CLIENT_KEY.to_string()),
    }
}

fn oauth_client_config(
    preferred: Option<&str>,
) -> Result<(&'static str, &'static str, String), String> {
    let key = resolve_oauth_client_key(preferred)?;
    Ok((CLIENT_ID, CLIENT_SECRET, key))
}

/// 生成 OAuth 授权 URL
pub fn get_auth_url(redirect_uri: &str, state: Option<&str>) -> String {
    let (client_id, _, _) = oauth_client_config(None).expect("默认 OAuth client 配置无效");
    let scopes = vec![
        "openid",
        "https://www.googleapis.com/auth/cloud-platform",
        "https://www.googleapis.com/auth/userinfo.email",
        "https://www.googleapis.com/auth/userinfo.profile",
        "https://www.googleapis.com/auth/cclog",
        "https://www.googleapis.com/auth/experimentsandconfigs",
    ]
    .join(" ");

    let mut params = vec![
        ("client_id", client_id),
        ("redirect_uri", redirect_uri),
        ("response_type", "code"),
        ("scope", &scopes),
        ("access_type", "offline"),
        ("prompt", "consent"),
    ];

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Keep calling get_auth_url with no preferred client (the only currently supported key) so the resolver returns the default.
  2. If adding a custom client, extend resolve_oauth_client_key to accept the new key instead of passing an unknown one.
  3. Change get_auth_url to return Result<String, String> and propagate the error from oauth_client_config instead of using .expect.

Example fix

// before
let (client_id, _, _) = oauth_client_config(None).expect("默认 OAuth client 配置无效");
// after
let (client_id, _, _) = oauth_client_config(None)?; // fn get_auth_url(...) -> Result<String, String>
Defensive patterns

Strategy: validation

Validate before calling

// Callers of get_auth_url today cannot trigger this (None is always Ok), but if you pass a preferred key:
const supported = ["default"];
if (preferred && !supported.includes(preferred.trim().toLowerCase())) {
  throw new Error(`未知 OAuth client: ${preferred}`);
}

Type guard

function isSupportedOAuthClient(key: string): boolean {
  return key.trim().toLowerCase() === 'default';
}

Try / catch

// Rust callers of a Result-returning variant:
let url = get_auth_url_checked(redirect_uri, state)
    .unwrap_or_else(|e| { log::error!("oauth config: {e}"); String::new() });

Prevention

When it happens

Trigger: Only when the call chain is modified so that get_auth_url forwards a preferred client identifier that is non-empty and does not equal DEFAULT_OAUTH_CLIENT_KEY (case-insensitively), causing resolve_oauth_client_key to return Err and .expect to panic.

Common situations: A developer adds multi-client support or a configurable client key and passes an unsupported/renamed key (e.g. a provider preset renamed or removed in a new version) into get_auth_url; end users never hit this directly.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/cbe462233b6a2106. Report an issue: GitHub.