hashicorp/nomad · error · ErrInvalidKeyIDHeader

%w; certificate-derived key header must be one of: %q, %q

Error message

%w; certificate-derived key header must be one of: %q, %q

What it means

When the OIDC client assertion is certificate-derived (pem_cert or pem_cert_file set), the KeyIDHeader must be either x5t (SHA-1 cert thumbprint) or x5tS256 (SHA-256 thumbprint). Any other header fails with ErrInvalidKeyIDHeader. Additionally, x5t is rejected outright when FIPS-140 mode is enabled because SHA-1 is forbidden.

Source

Thrown at nomad/structs/acl.go:1897

	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
// evaluation.
type ACLAuthClaims struct {
	Value map[string]string   `bexpr:"value"`
	List  map[string][]string `bexpr:"list"`
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set key_id_header to "x5tS256" (preferred) or "x5t" for certificate-derived assertions.
  2. If in FIPS-140 mode, use x5tS256 and ensure your IdP accepts SHA-256 thumbprints.
  3. Verify the exact header constant spelling ("x5tS256", not "x5t256").

Example fix

// before
pem_cert_file = "/etc/ssl/client.crt"
key_id_header = "kid"

// after
pem_cert_file = "/etc/ssl/client.crt"
key_id_header = "x5tS256"
Defensive patterns

Strategy: validation

Validate before calling

if (k.PemCert != "" || k.PemCertFile != "") {
    switch k.KeyIDHeader {
    case "x5t", "x5tS256":
    default:
        return fmt.Errorf("cert-based assertion needs x5t or x5tS256 header, got %q", k.KeyIDHeader)
    }
    if fipsEnabled && k.KeyIDHeader == "x5t" {
        return errors.New("x5t forbidden in FIPS mode; use x5tS256")
    }
}

Prevention

When it happens

Trigger: Setting key_id_header to "kid" (or anything else) while pem_cert/pem_cert_file are configured; or using "x5t" on a Nomad server running with FIPS-140 mode enabled.

Common situations: Swapping a key_id config to cert-based without updating the header; Azure AD setups needing x5t while the Nomad server is in FIPS mode; typo like "x5t256" instead of "x5tS256".

Understand the failure class

Related errors


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