{"record":{"id":"53ec7371b7985139","repo":"hashicorp/nomad","slug":"failed-to-build-client-assertion-jwt-w","errorCode":null,"errorMessage":"failed to build client_assertion jwt: %w","messagePattern":"failed to build client_assertion jwt: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/acl_endpoint.go","lineNumber":3171,"sourceCode":"\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create OIDC request: %v\", err)\n\t}\n\n\treturn req, nil\n}\n\nfunc (a *ACL) oidcClientAssertion(config *structs.ACLAuthMethodConfig) (*cass.JWT, error) {\n\t// this nomad key will only actually be used if the client assertion config\n\t// KeySource = \"nomad\", but we get it here to avoid exposing more of the\n\t// codebase to the encrypter.\n\tnomadKey, nomadKID, err := a.srv.encrypter.GetActiveKey()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get active nomad key: %w\", err)\n\t}\n\tj, err := oidc.BuildClientAssertionJWT(config, nomadKey, nomadKID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build client_assertion jwt: %w\", err)\n\t}\n\tif config.VerboseLogging {\n\t\t// a user initially setting up the auth method, as one might with\n\t\t// VerboseLogging enabled, may benefit from not having to do a full\n\t\t// login flow to see the jwt (and any possible Serialize() error).\n\t\t// we say \"example\" in the log, because the cap library will run\n\t\t// Serialize() again internally, so it won't use this same jwt.\n\t\ttoken, err := j.Serialize()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to serialize client_assertion jwt: %w\", err)\n\t\t}\n\t\ta.logger.Debug(\"example client_assertion\", \"oidc_client_id\", config.OIDCClientID, \"jwt\", token)\n\t}\n\treturn j, nil\n}\n\nfunc (a *ACL) CreateClientIntroductionToken(\n\targs *structs.ACLCreateClientIntroductionTokenRequest,","sourceCodeStart":3153,"sourceCodeEnd":3189,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/acl_endpoint.go#L3153-L3189","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n\"OIDCClientAssertion\": { \"KeySource\": \"private-key\", \"PrivateKey\": \"<bad-pem>\", \"SigningAlgorithm\": \"ES256\" }\n// after: matching key type and valid PEM\n\"OIDCClientAssertion\": { \"KeySource\": \"private-key\", \"PrivateKey\": \"-----BEGIN EC PRIVATE KEY-----...\", \"SigningAlgorithm\": \"ES256\" }","handlingStrategy":"validation","validationCode":"// preflight: key parses and matches the signing algorithm\nblk, _ := pem.Decode([]byte(cfg.OIDCClientAssertion.PrivateKey))\nif blk == nil { return errors.New(\"invalid PEM\") }\nkey, err := x509.ParseECPrivateKey(blk.Bytes)\nif err != nil && cfg.OIDCClientAssertion.SigningAlgorithm == \"ES256\" {\n  return errors.New(\"ES256 requires an EC key\")\n}\nif cfg.OIDCClientID == \"\" { return errors.New(\"OIDCClientID required for client assertion\") }","typeGuard":null,"tryCatchPattern":"j, err := oidc.BuildClientAssertionJWT(config, nomadKey, nomadKID)\nif err != nil {\n    return nil, fmt.Errorf(\"failed to build client_assertion jwt: %w\", err)\n}","preventionTips":["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."],"tags":["jwt","oidc","client-assertion","nomad"],"backgroundTag":"jwt-signing-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}