nats-io/nats-server · error

auth callout violation: auth callout response is not for ser

Error message

auth callout violation: auth callout response is not for server

What it means

This error is raised during auth callout processing when the authorization response's Audience does not equal the server's ID (s.info.ID). The audience check prevents a response intended for one server from being replayed against another. A mismatched audience means the response was not issued for this server and authentication is rejected.

Source

Thrown at server/auth_callout.go:132

		cr, err := jwt.DecodeAuthorizationResponseClaims(string(msg))
		if err != nil {
			return nil, err
		}
		vr := jwt.CreateValidationResults()
		cr.Validate(vr)
		if len(vr.Issues) > 0 {
			return nil, fmt.Errorf("authorization response had validation errors: %v", vr.Issues[0])
		}

		// the subject is the user id
		if cr.Subject != pub {
			return nil, errors.New("auth callout violation: auth callout response is not for expected user")
		}

		// check the audience to be the server ID
		if cr.Audience != s.info.ID {
			return nil, errors.New("auth callout violation: auth callout response is not for server")
		}

		// check if had an error message from the auth account
		if cr.Error != _EMPTY_ {
			return nil, fmt.Errorf("auth callout service returned an error: %v", cr.Error)
		}

		// if response is encrypted none of this is needed
		if isOperatorMode && !encrypted {
			pkStr := cr.Issuer
			if cr.IssuerAccount != _EMPTY_ {
				pkStr = cr.IssuerAccount
			}
			if pkStr != account {
				if _, ok := acc.hasIssuer(pkStr); !ok {
					return nil, errors.New("auth callout signing key is unknown")
				}
			}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Set the response Audience to the server ID taken from the AuthorizationRequest's ServerID (or Audience) field, not a static value
  2. Make the callout service derive Audience per-request instead of hardcoding it
  3. If running a cluster, ensure each server gets responses issued with its own server ID (no cross-server response reuse)
  4. Clear any cached authorization responses after server ID changes

Example fix

// before
resp.Audience = "my-server" // hardcoded
// after
resp.Audience = req.Server.ID // server ID from the incoming AuthorizationRequest
Defensive patterns

Strategy: try-catch

Validate before calling

// callout service: derive audience from the request
if req.Server.ID == "" {
    return fmt.Errorf("no server id in authorization request")
}
resp.Audience = req.Server.ID

Try / catch

user, err := s.lookupAccountAuthorization(...)
if err != nil && strings.Contains(err.Error(), "not for server") {
    log.Errorf("callout audience mismatch; response not issued for server %s", s.info.ID)
    return nil, ErrAuthorization
}

Prevention

When it happens

Trigger: A client connects, the auth callout service responds, but the AuthorizationResponse's Audience field differs from the receiving server's server ID.

Common situations: Hardcoded or wrong Audience in the callout service config, responses reused across clustered servers with different IDs, or server ID changes after restart/upgrade while the service caches responses.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/8652363afd80584d. Report an issue: GitHub.