nats-io/nats-server · error
authorization response had validation errors: %v
Error message
authorization response had validation errors: %v
What it means
The server validated the authorization response claims (AuthorizationResponseClaims, cr) returned by an auth callout service using jwt.CreateValidationResults/Validate, and at least one generic JWT claim was invalid (only the first issue is reported). This is thrown when the callout's response JWT fails structural/temporal validation (e.g. expired, malformed claims) before the server will trust it. The auth callout contract requires a well-formed, currently valid response JWT.
Source
Thrown at server/auth_callout.go:122
// If we sent an encrypted request the response could be encrypted as well.
// we are expecting the input to be `eyJ` if it is a JWT
if xkp != nil && len(msg) > 0 && !bytes.HasPrefix(msg, []byte(jwtPrefix)) {
var err error
msg, err = xkp.Open(msg, pubAccXKey)
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 neededView on GitHub (pinned to 3a66a489d2)
Solutions
- Sync the callout service's clock (NTP) so issued JWTs are temporally valid.
- Log vr.Issues server-side or replicate cr.Validate(vr) in the callout to see the exact failing claim and fix claim construction.
- Ensure the callout library/jwt package version matches what the server validates against.
- Set proper Issuer, Subject, Audience and times in the AuthorizationResponseClaims before signing.
Example fix
// before
cr := jwt.NewAuthorizationResponseClaims(pub, issuer)
cr.Expires = time.Now().Add(-time.Minute) // stale/expired
// after
cr := jwt.NewAuthorizationResponseClaims(pub, issuer)
cr.Expires = time.Now().Add(2 * time.Minute)
vr := jwt.CreateValidationResults()
cr.Validate(vr)
if len(vr.Issues) > 0 { /* fix claims before publishing */ } Defensive patterns
Strategy: validation
Validate before calling
vr := jwt.CreateValidationResults()
cr.Validate(vr)
if len(vr.Issues) > 0 {
return fmt.Errorf("response claims invalid: %v", vr.Issues)
} Try / catch
resp, err := doAuthCallout()
if err != nil {
var verr *ValidationErr
if errors.As(err, &verr) { /* regenerate claims, resync clock */ }
return err
} Prevention
- Validate claims with cr.Validate(vr) in the callout before publishing.
- Run NTP on all hosts issuing and validating JWTs.
- Keep the jwt library version in the callout in sync with the server.
When it happens
Trigger: An auth callout service publishes an AuthorizationResponseClaims JWT whose Validate() reports issues: expired or not-yet-valid nbf, missing/invalid issuer or subject, bad times format, or a claim violating jwt generic claim rules.
Common situations: Callout service clock skew producing expired/early JWTs; callout built against an older JWT library emitting claims the server's jwt package rejects; hand-rolled claim construction leaving required fields empty.
Related errors
- operators do not allow authorization callouts to be configur
- malformed request
- validation errors: %v
- error non operator mode account %q: attempted to use issuer_
- wrong issuer for auth callout response on account %q, expect
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/9a33d2b8abbeb588.
Report an issue: GitHub.