windmill-labs/windmill · error
invalid secret
Error message
invalid secret
What it means
SlackVerifier::new initializes an HMAC-SHA256 machine from the Slack signing secret. HMAC accepts any key length in practice, so new_from_slice failing is unexpected; the constructor maps any failure to 'invalid secret' rather than returning a verifier.
Source
Thrown at backend/windmill-oauth/src/lib.rs:1114
cookie.set_http_only(true);
cookie.set_path("/");
if COOKIE_DOMAIN.is_some() {
cookie.set_domain(COOKIE_DOMAIN.clone().unwrap());
}
cookies.add(cookie);
}
/// Slack signature verifier for webhook authentication
#[derive(Clone, Debug)]
pub struct SlackVerifier {
mac: HmacSha256,
}
impl SlackVerifier {
pub fn new<S: AsRef<[u8]>>(secret: S) -> anyhow::Result<SlackVerifier> {
HmacSha256::new_from_slice(secret.as_ref())
.map(|mac| SlackVerifier { mac })
.map_err(|_| anyhow::anyhow!("invalid secret"))
}
pub fn verify(&self, ts: &str, body: &str, exp_sig: &str) -> anyhow::Result<()> {
let basestring = format!("v0:{}:{}", ts, body);
let mut mac = self.mac.clone();
mac.update(basestring.as_bytes());
let sig = format!("v0={}", hex::encode(mac.finalize().into_bytes()));
if sig != exp_sig {
Err(anyhow::anyhow!("signature mismatch"))?;
}
Ok(())
}
}
/// Fetch user info from OAuth provider
pub async fn http_get_user_info<T: DeserializeOwned>(
http_client: &reqwest::Client,View on GitHub (pinned to e474e8803c)
Solutions
- Ensure the Slack signing secret is configured (from Slack app 'Signing Secret' under Basic Information) and non-empty
- Check the env var / config key actually reaches the code that constructs SlackVerifier
- If storing the secret in the DB or a file, verify no empty-string fallback is being used
Example fix
// before
let verifier = SlackVerifier::new("")?; // fails
// after
let verifier = SlackVerifier::new(std::env::var("SLACK_SIGNING_SECRET")?)?; Defensive patterns
Strategy: validation
Validate before calling
let secret = std::env::var("SLACK_SIGNING_SECRET")?;
if secret.is_empty() { anyhow::bail!("SLACK_SIGNING_SECRET is not set"); }
let verifier = SlackVerifier::new(&secret)?; Type guard
fn usable_signing_secret(s: &str) -> bool { !s.trim().is_empty() } Try / catch
match SlackVerifier::new(&secret) {
Ok(v) => v,
Err(e) if e.to_string() == "invalid secret" => {
anyhow::bail!("Signing secret missing/empty — configure SLACK_SIGNING_SECRET");
}
Err(e) => return Err(e),
} Prevention
- Fail fast at startup if the Slack signing secret env var is missing or empty
- Store secrets in a secrets manager rather than optional config fields that default to empty strings
When it happens
Trigger: SlackVerifier::new called with a secret that HmacSha256::new_from_slice rejects — in practice only when the secret is empty or the HMAC construction fails internally.
Common situations: Empty SLACK_SIGNING_SECRET / signing secret env var not set; a None/empty string passed through from config instead of the real secret.
Related errors
- signature mismatch
- No local instance profile named ${instanceName}
- No active instance. Run 'wmill instance add' or pass --insta
- ${what} failed:\n${output}
- No instance found, please add one first
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/c4b4ab85b8c8893b.
Report an issue: GitHub.