nats-io/nats-server · error
auth callout violation: auth callout response is not for exp
Error message
auth callout violation: auth callout response is not for expected user
What it means
This error is raised during authorization-callout processing when the auth callout service returns an authorization response whose Subject does not match the user id (public key) that initiated the request. The server treats a mismatched subject as a protocol/security violation and rejects the authentication. It ensures the callout service cannot authorize a different user than the one being checked.
Source
Thrown at server/auth_callout.go:127
if err != nil {
return nil, fmt.Errorf("error decrypting auth callout response on account %q: %v", account, err)
}
encrypted = true
}
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
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the auth callout service to set Subject in the AuthorizationResponse to the exact public key (user id) from the AuthorizationRequest
- Ensure the callout service does not cache or replay responses across different users
- Log the expected pub and returned cr.Subject on the callout service side to find the mismatch
- Verify the service decodes the request JWT with the correct key so it reads the right user id
Example fix
// before (callout service) resp.Subject = requestUserAccount // wrong field // after resp.Subject = req.UserNonceClaim / decodedReq.Subject // the connecting user's public key
Defensive patterns
Strategy: try-catch
Validate before calling
// client side: ensure the callout service sets Subject to your public key
// server side: nothing to pre-validate; fix in callout service
if resp.Subject != expectedPubKey {
return fmt.Errorf("callout subject mismatch: got %s want %s", resp.Subject, expectedPubKey)
} Try / catch
user, err := s.lookupAccountAuthorization(...) // callout path
if err != nil && strings.Contains(err.Error(), "not for expected user") {
log.Errorf("callout service returned wrong subject; check callout service config")
return nil, ErrAuthorization
} Prevention
- Callout service must echo the request's subject exactly
- Avoid caching/replaying authorization responses across users
- Integration-test the callout flow with real user credentials
When it happens
Trigger: A client connects and triggers the auth callout; the authorization response (AuthorizationResponse claims) contains a Subject field different from the connecting user's public key passed to the check.
Common situations: A misconfigured auth callout service echoing the wrong subject, reusing cached responses across users, signing responses for a different account/user, or a bug where the service derives Subject from the wrong request field.
Related errors
- auth callout violation: auth callout response is not for ser
- 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/7b7f00c3f897d60b.
Report an issue: GitHub.