hashicorp/nomad · error · ErrInvalidKeyIDHeader
%w; key header for key ID must be %q
Error message
%w; key header for key ID must be %q
What it means
When an OIDC client assertion uses a KeyID (key_id), the kid JWT header is the only permitted KeyIDHeader. Any other header value (x5t, x5tS256, custom) fails validation with ErrInvalidKeyIDHeader. This enforces the JWT spec mapping: a raw key id maps to the `kid` header.
Source
Thrown at nomad/structs/acl.go:1891
if k.PemCert != "" && (k.PemCertFile != "" || k.KeyID != "") {
return ErrAmbiguousClientAssertionKeyID
}
if k.PemCertFile != "" && (k.PemCert != "" || k.KeyID != "") {
return ErrAmbiguousClientAssertionKeyID
}
if k.KeyID != "" && (k.PemCert != "" || k.PemCertFile != "") {
return ErrAmbiguousClientAssertionKeyID
}
if k.PemCertFile != "" {
if !path.IsAbs(k.PemCertFile) {
return fmt.Errorf("%w: must be absolute; got: %s", ErrInvalidClientAssertionCertPath, k.PemCertFile)
}
}
// only allow certain key id headers
// only "kid" for KeyID
if k.KeyID != "" && k.KeyIDHeader != OIDCClientAssertionHeaderKid {
return fmt.Errorf("%w; key header for key ID must be %q",
ErrInvalidKeyIDHeader, OIDCClientAssertionHeaderKid)
}
// only "x5t*" for certs
if k.PemCert != "" || k.PemCertFile != "" {
if k.KeyIDHeader != OIDCClientAssertionHeaderX5t && k.KeyIDHeader != OIDCClientAssertionHeaderX5tS256 {
return fmt.Errorf("%w; certificate-derived key header must be one of: %q, %q",
ErrInvalidKeyIDHeader, OIDCClientAssertionHeaderX5tS256, OIDCClientAssertionHeaderX5t)
}
if fips140.Enabled() && k.KeyIDHeader == OIDCClientAssertionHeaderX5t {
return errors.New("x5t assertion headers use SHA-1, which is forbidden in FIPS-140 mode")
}
}
return nil
}
// ACLAuthClaims is the claim mapping of the OIDC auth method in a format that
// can be used with go-bexpr. This structure is used during rule bindingView on GitHub (pinned to 482b49bf1a)
Solutions
- Set key_id_header to "kid" (OIDCClientAssertionHeaderKid).
- If your IdP requires x5t, provide cert material (pem_cert/pem_cert_file) instead of key_id.
- Re-validate the provider config.
Example fix
// before key_id = "my-key-id" key_id_header = "x5t" // after key_id = "my-key-id" key_id_header = "kid"
Defensive patterns
Strategy: validation
Validate before calling
if k.KeyID != "" && k.KeyIDHeader != "kid" {
return fmt.Errorf("key_id requires key_id_header=kid, got %q", k.KeyIDHeader)
} Prevention
- Pair key_id exclusively with the kid header.
- Use cert material (pem_cert) when your IdP requires x5t.
- Document header/key pairing in your config templates.
When it happens
Trigger: Configuring an OIDC client assertion with key_id set while key_id_header is "x5t", "x5tS256", or any non-"kid" value.
Common situations: Copy-pasting a cert-based assertion config (which uses x5t) and only swapping in a key_id; misunderstanding the header/key correspondence in the IdP (e.g. Azure AD expects x5t for certs).
Related errors
- invalid config: %w
- %w; certificate-derived key header must be one of: %q, %q
- missing OIDCDiscoveryURL
- missing OIDCClientID
- JWT auth method requires either OIDCDiscoveryURL, or JWKS UR
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/6efcd22d83d33030.
Report an issue: GitHub.