hashicorp/nomad · error

missing client nonce

Error message

missing client nonce

What it means

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.

Solutions

  1. Generate a secure random nonce (e.g. uuid) and set ClientNonce before the request
  2. Reuse the Nomad CLI's login flow instead of hand-rolling the auth-url call
  3. Ensure the same nonce is supplied when completing the flow

Example fix

// before
req := &structs.ACLOIDCAuthURLRequest{AuthMethodName: "auth0", RedirectURI: redirect}
// after
req := &structs.ACLOIDCAuthURLRequest{AuthMethodName: "auth0", RedirectURI: redirect, ClientNonce: uuid.Generate()}
Defensive patterns

Strategy: validation

Validate before calling

if req.ClientNonce == "" { return errors.New("ClientNonce must be a generated random nonce") }

Type guard

func hasNonce(req *structs.ACLOIDCAuthURLRequest) bool { return req != nil && req.ClientNonce != "" }

Try / catch

if err := req.Validate(); err != nil {
  if strings.Contains(err.Error(), "missing client nonce") {
    req.ClientNonce = uuid.Generate() // regenerate and retry once
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: Custom OIDC login tooling against Nomad's HTTP API omitting ClientNonce; reusing CLI code paths but dropping nonce generation; test harnesses constructing partial requests.

Related errors


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

Appendix: source

Thrown at nomad/structs/acl.go:2334

	ClientNonce string

	// WriteRequest is used due to the requirement by the RPC forwarding
	// mechanism. This request doesn't write anything to Nomad's internal
	// state.
	WriteRequest
}

// Validate ensures the request object contains all the required fields in
// order to start the OIDC authentication flow.
func (a *ACLOIDCAuthURLRequest) Validate() error {

	var mErr multierror.Error

	if a.AuthMethodName == "" {
		mErr.Errors = append(mErr.Errors, errors.New("missing auth method name"))
	}
	if a.ClientNonce == "" {
		mErr.Errors = append(mErr.Errors, errors.New("missing client nonce"))
	}
	if a.RedirectURI == "" {
		mErr.Errors = append(mErr.Errors, errors.New("missing redirect URI"))
	}
	return mErr.ErrorOrNil()
}

// ACLOIDCAuthURLResponse is the response when starting the OIDC authentication
// login flow.
type ACLOIDCAuthURLResponse struct {

	// AuthURL is URL to begin authorization and is where the user logging in
	// should go.
	AuthURL string
}

// ACLOIDCCompleteAuthRequest is the request object to begin completing the
// OIDC auth cycle after receiving the callback from the OIDC provider.

View on GitHub (pinned to 482b49bf1a)