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
- Set the response Audience to the server ID taken from the AuthorizationRequest's ServerID (or Audience) field, not a static value
- Make the callout service derive Audience per-request instead of hardcoding it
- If running a cluster, ensure each server gets responses issued with its own server ID (no cross-server response reuse)
- 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
- Never hardcode the server ID in callout service config
- Re-derive Audience per request from the incoming AuthorizationRequest
- Invalidate cached responses when server IDs change (upgrades, cluster changes)
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
- auth callout violation: auth callout response is not for exp
- auth callout signing key is unknown
- not trusted
- account jwt not found
- account validation failed
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/8652363afd80584d.
Report an issue: GitHub.