hashicorp/nomad · error
failed to build client_assertion jwt: %w
Error message
failed to build client_assertion jwt: %w
What it means
Thrown by oidcClientAssertion when oidc.BuildClientAssertionJWT fails to build the signed private_key_jwt client_assertion JWT from the auth method config and the active Nomad key. The config's signing algorithm, key, or required OIDC fields (issuer, client id, token URL) are inconsistent with what the JWT builder requires.
Source
Thrown at nomad/acl_endpoint.go:3171
)
if err != nil {
return nil, fmt.Errorf("failed to create OIDC request: %v", err)
}
return req, nil
}
func (a *ACL) oidcClientAssertion(config *structs.ACLAuthMethodConfig) (*cass.JWT, error) {
// this nomad key will only actually be used if the client assertion config
// KeySource = "nomad", but we get it here to avoid exposing more of the
// codebase to the encrypter.
nomadKey, nomadKID, err := a.srv.encrypter.GetActiveKey()
if err != nil {
return nil, fmt.Errorf("failed to get active nomad key: %w", err)
}
j, err := oidc.BuildClientAssertionJWT(config, nomadKey, nomadKID)
if err != nil {
return nil, fmt.Errorf("failed to build client_assertion jwt: %w", err)
}
if config.VerboseLogging {
// a user initially setting up the auth method, as one might with
// VerboseLogging enabled, may benefit from not having to do a full
// login flow to see the jwt (and any possible Serialize() error).
// we say "example" in the log, because the cap library will run
// Serialize() again internally, so it won't use this same jwt.
token, err := j.Serialize()
if err != nil {
return nil, fmt.Errorf("failed to serialize client_assertion jwt: %w", err)
}
a.logger.Debug("example client_assertion", "oidc_client_id", config.OIDCClientID, "jwt", token)
}
return j, nil
}
func (a *ACL) CreateClientIntroductionToken(
args *structs.ACLCreateClientIntroductionTokenRequest,View on GitHub (pinned to 482b49bf1a)
Solutions
- Read the wrapped cause; align the signing algorithm with the key type (e.g. use ES256/EdDSA only with matching keys).
- Verify OIDCClientID and the provider discovery URL are set — they populate iss/aud claims in the assertion.
- If KeySource is 'private-key', check the PEM key parses (openssl pkey -in key.pem) and matches the configured algorithm.
- Test the assertion JWT at the IdP or enable VerboseLogging to see the serialized example JWT.
Example fix
// before
"OIDCClientAssertion": { "KeySource": "private-key", "PrivateKey": "<bad-pem>", "SigningAlgorithm": "ES256" }
// after: matching key type and valid PEM
"OIDCClientAssertion": { "KeySource": "private-key", "PrivateKey": "-----BEGIN EC PRIVATE KEY-----...", "SigningAlgorithm": "ES256" } Defensive patterns
Strategy: validation
Validate before calling
// preflight: key parses and matches the signing algorithm
blk, _ := pem.Decode([]byte(cfg.OIDCClientAssertion.PrivateKey))
if blk == nil { return errors.New("invalid PEM") }
key, err := x509.ParseECPrivateKey(blk.Bytes)
if err != nil && cfg.OIDCClientAssertion.SigningAlgorithm == "ES256" {
return errors.New("ES256 requires an EC key")
}
if cfg.OIDCClientID == "" { return errors.New("OIDCClientID required for client assertion") } Try / catch
j, err := oidc.BuildClientAssertionJWT(config, nomadKey, nomadKID)
if err != nil {
return nil, fmt.Errorf("failed to build client_assertion jwt: %w", err)
} Prevention
- Match SigningAlgorithm to the key type before saving the auth method.
- Validate PEM keys with openssl when switching KeySource to private-key.
- Always set OIDCClientID and a correct discovery URL.
When it happens
Trigger: oidc.BuildClientAssertionJWT(config, nomadKey, nomadKID) errors — typically unsupported signing algorithm for the supplied key (e.g. RS256 vs EdDSA key), missing OIDCClientID / discovery URL needed for issuer/audience claims, or malformed private key material in OIDCClientAssertion.
Common situations: Static private key pasted with wrong PEM encoding or wrong key type for the configured algorithm, KeySource='nomad' used where the key algorithm does not match the IdP's expectations, missing OIDCClientID in the auth method config.
Related errors
- invalid KeyIDHeader
- failed to serialize client_assertion jwt: %w
- no auth method config or client assertion
- missing Audience
- PrivateKey is required for `private_key` KeySource
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/53ec7371b7985139.
Report an issue: GitHub.