nats-io/nats-server · error

operators do not allow authorization callouts to be configur

Error message

operators do not allow authorization callouts to be configured directly

What it means

When operator mode is in effect (trusted operators / JWT-based auth), all authorization must be managed via account-scoped authorization callouts declared in operator/account JWTs, not via the server's own configuration. If `authorization {}` (AuthCallout) is set directly in server config while operator mode is enabled, `validateTrustedOperators` in server/jwt.go:176 rejects the configuration at startup.

Source

Thrown at server/jwt.go:176

		if !nkeys.IsValidPublicOperatorKey(key) {
			return fmt.Errorf("trusted Keys %q are required to be a valid public operator nkey", key)
		}
	}
	if len(o.resolverPinnedAccounts) > 0 {
		for key := range o.resolverPinnedAccounts {
			if !nkeys.IsValidPublicAccountKey(key) {
				return fmt.Errorf("pinned account key %q is not a valid public account nkey", key)
			}
		}
		// ensure the system account (belonging to the operator can always connect)
		if o.SystemAccount != _EMPTY_ {
			o.resolverPinnedAccounts[o.SystemAccount] = struct{}{}
		}
	}

	// If we have an auth callout defined make sure we are not in operator mode.
	if o.AuthCallout != nil {
		return errors.New("operators do not allow authorization callouts to be configured directly")
	}

	return nil
}

func validateSrc(claims *jwt.UserClaims, host string) bool {
	if claims == nil {
		return false
	} else if len(claims.Src) == 0 {
		return true
	} else if host == "" {
		return false
	}
	ip := net.ParseIP(host)
	if ip == nil {
		return false
	}
	for _, cidr := range claims.Src {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Remove the `authorization { ... }` callout block from the server config and define the auth callout in an account JWT instead (pushed via resolver or embedded)
  2. If direct auth callout is intended, remove the trusted operator/operator mode configuration
  3. Move any user-level auth into account/user JWTs managed by the operator's signing key

Example fix

// before: operator mode + direct callout in nats-server.conf
resolver: URL(...)
authorization {
  users = [ ... ]
}
// after: authorization via account JWT only
resolver: URL(...)
// (authorization block removed; callout configured in the account JWT)
Defensive patterns

Strategy: validation

Validate before calling

// Reject the config combination before startup
if hasTrustedOperators(cfg) && cfg.Authorization != nil {
  return errors.New("auth callout cannot be configured directly in operator mode")
}

Prevention

When it happens

Trigger: Starting a server with both a resolver/operator JWT setup (trusted operators) and a direct `authorization { ... }` block in the config file; enabling operator mode via `--trusted` while auth callout options remain present.

Common situations: Migrating a self-managed server to operator mode and forgetting to remove the legacy auth callout block; copying a config from a non-operator deployment into an operator-mode deployment; enabling trusted operators in a test config that still has auth callout settings.

Related errors


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