{"record":{"id":"27d76318c4c7a981","repo":"hashicorp/nomad","slug":"missing-client-nonce","errorCode":null,"errorMessage":"missing client nonce","messagePattern":"missing client nonce","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/acl.go","lineNumber":2334,"sourceCode":"\tClientNonce string\n\n\t// WriteRequest is used due to the requirement by the RPC forwarding\n\t// mechanism. This request doesn't write anything to Nomad's internal\n\t// state.\n\tWriteRequest\n}\n\n// Validate ensures the request object contains all the required fields in\n// order to start the OIDC authentication flow.\nfunc (a *ACLOIDCAuthURLRequest) Validate() error {\n\n\tvar mErr multierror.Error\n\n\tif a.AuthMethodName == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"missing auth method name\"))\n\t}\n\tif a.ClientNonce == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"missing client nonce\"))\n\t}\n\tif a.RedirectURI == \"\" {\n\t\tmErr.Errors = append(mErr.Errors, errors.New(\"missing redirect URI\"))\n\t}\n\treturn mErr.ErrorOrNil()\n}\n\n// ACLOIDCAuthURLResponse is the response when starting the OIDC authentication\n// login flow.\ntype ACLOIDCAuthURLResponse struct {\n\n\t// AuthURL is URL to begin authorization and is where the user logging in\n\t// should go.\n\tAuthURL string\n}\n\n// ACLOIDCCompleteAuthRequest is the request object to begin completing the\n// OIDC auth cycle after receiving the callback from the OIDC provider.","sourceCodeStart":2316,"sourceCodeEnd":2352,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/acl.go#L2316-L2352","documentation":"ACLOIDCAuthURLRequest.Validate requires ClientNonce to be non-empty. The nonce ties the generated OIDC auth URL to a client session so the callback can be verified against the original request. An empty nonce means the flow cannot be validated, so 'missing client nonce' is appended.","triggerScenarios":"Calling the OIDC auth-url endpoint with ACLOIDCAuthURLRequest.ClientNonce == \"\", e.g. an API client that builds the request manually without generating a nonce (the Nomad CLI normally generates one).","commonSituations":"Custom OIDC login tooling against Nomad's HTTP API omitting ClientNonce; reusing CLI code paths but dropping nonce generation; test harnesses constructing partial requests.","solutions":["Generate a secure random nonce (e.g. uuid) and set ClientNonce before the request","Reuse the Nomad CLI's login flow instead of hand-rolling the auth-url call","Ensure the same nonce is supplied when completing the flow"],"exampleFix":"// before\nreq := &structs.ACLOIDCAuthURLRequest{AuthMethodName: \"auth0\", RedirectURI: redirect}\n// after\nreq := &structs.ACLOIDCAuthURLRequest{AuthMethodName: \"auth0\", RedirectURI: redirect, ClientNonce: uuid.Generate()}","handlingStrategy":"validation","validationCode":"if req.ClientNonce == \"\" { return errors.New(\"ClientNonce must be a generated random nonce\") }","typeGuard":"func hasNonce(req *structs.ACLOIDCAuthURLRequest) bool { return req != nil && req.ClientNonce != \"\" }","tryCatchPattern":"if err := req.Validate(); err != nil {\n  if strings.Contains(err.Error(), \"missing client nonce\") {\n    req.ClientNonce = uuid.Generate() // regenerate and retry once\n  }\n}","preventionTips":["Generate a fresh random nonce for every login flow","Keep nonce generation in a shared helper so it cannot be omitted","Reuse the Nomad CLI login implementation rather than hand-building requests"],"tags":["nomad","acl","oidc","validation","nonce"],"backgroundTag":"missing-oidc-nonce","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"}