clockworklabs/SpacetimeDB · error · TokenValidationError
No kid found
Error message
No kid found
What it means
JwksValidator first tries the token header's kid against the keyset (a miss there yields KeyIDNotFound); 'No kid found' is the seed error of the fallback loop that tries every key, and it survives to the caller only when the keyset has no keys to try (or the loop never runs). In practice: the token header lacks a kid AND the fetched JWKS keyset is empty or unusable.
Solutions
- Curl the issuer's jwks_uri and confirm the keys array is non-empty; fix the provider/rotation state if it is empty
- Ensure your token signer sets the kid header to a key present in the published JWKS
- If you control both sides, publish at least one key and mint tokens referencing it via kid
Defensive patterns
Strategy: validation
Validate before calling
# bash: confirm the JWKS actually publishes keys before wiring auth curl -fsS "$JWKS_URI" | grep -q '"kid"' || echo "JWKS has no usable keys"
Prevention
- Ensure your token signer always sets the kid header referencing a published key
- Alert when a JWKS keys array becomes empty (rotation bug) instead of waiting for auth failures
When it happens
Trigger: Presenting a token whose header omits kid to a validator whose JWKS keys map is empty — e.g. the endpoint returned {"keys":[]}, keys are mid-rotation, or a stubbed/dev OIDC setup publishes no keys.
Common situations: Custom or internal OIDC providers that omit kid in signed tokens; JWKS endpoints misconfigured or returning empty sets; test harnesses with stub keysets.
Related errors
- Error fetching public key for issuer
- Issuer mismatch: got
- Invalid JSON: failed to parse string
- Invalid OIDC URL scheme
- Issuer empty
AI-assisted analysis of clockworklabs/SpacetimeDB@3653d2ed49 (2026-09-06).
Data as JSON: /api/errors/f79b70bc4deb60ef.
Report an issue: GitHub.
Appendix: source
Thrown at crates/core/src/auth/token_validation.rs:332
}
log::debug!("Key id {kid} not found in JWKS. Trying keys without key ids.");
let mut last_error = TokenValidationError::KeyIDNotFound;
for key in self.keyset.keys_without_ids() {
match self.validate_with_key(token, key).await {
Ok(claims) => return Ok(claims),
Err(e) => {
last_error = e;
log::debug!("Validating with key without kid failed");
}
}
}
return Err(last_error);
}
log::debug!("No key id in header. Trying all keys.");
// TODO: Consider returning an error if no kid is given?
// For now, lets just try all the keys.
let mut last_error = TokenValidationError::Other(anyhow::anyhow!("No kid found"));
for key in &self.keyset.keys {
match &key.kid {
Some(kid) => log::debug!("Trying key {kid}"),
None => log::debug!("Trying key without kid"),
}
match self.validate_with_key(token, key).await {
Ok(claims) => return Ok(claims),
Err(e) => {
last_error = e;
log::debug!("Validating with JWKS key failed");
continue;
}
}
}
// None of the keys worked.
Err(last_error)
}
}View on GitHub (pinned to 3653d2ed49)