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 binding

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set key_id_header to "kid" (OIDCClientAssertionHeaderKid).
  2. If your IdP requires x5t, provide cert material (pem_cert/pem_cert_file) instead of key_id.
  3. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/6efcd22d83d33030. Report an issue: GitHub.