nats-io/nats-server · error
auth callout signing key is unknown
Error message
auth callout signing key is unknown
What it means
This error occurs when the auth callout response is signed by a key (Issuer, or IssuerAccount if set) that is not the expected account and is not a known signing key of that account. The server verifies that whoever signed the authorization response is authorized (via account issuer keys) to do so; an unknown signer is a security violation.
Source
Thrown at server/auth_callout.go:148
// 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")
}
}
}
return jwt.DecodeUserClaims(cr.Jwt)
}
// getIssuerAccount returns the issuer (as per JWT) - it also asserts that
// only in operator mode we expect to receive `issuer_account`.
getIssuerAccount := func(arc *jwt.UserClaims, account string) (string, error) {
// Make sure correct issuer.
var issuer string
if opts.AuthCallout != nil {
issuer = opts.AuthCallout.Issuer
} else {
// Operator mode is who we send the request on unless switching accounts.
issuer = acc.Name
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Add the callout service's signing public key to the account's trusted signing/issuer keys (nsc edit account --signing-key or equivalent)
- Ensure cr.IssuerAccount, when set, matches an account that is a valid issuer for the target account
- Re-sign the authorization response with a key already registered on the account
- Push the updated account JWT to the server after adding the issuer key
Example fix
// before nsc add operator -n ops // service signs with a key unknown to account // after nsc edit account AUTH --signing-key <callout-service-public-key> nsc push -A
Defensive patterns
Strategy: validation
Validate before calling
// before deploying: verify the signing key is a registered account signing key
acctJWT, _ := fetchAccountJWT(accountPub)
claims, _ := jwt.DecodeAccountClaims(acctJWT)
found := false
for k := range claims.SigningKeys {
if k == calloutSigningPubKey {
found = true
}
}
if !found {
return fmt.Errorf("callout signing key %s not registered on account", calloutSigningPubKey)
} Try / catch
user, err := s.lookupAccountAuthorization(...)
if err != nil && strings.Contains(err.Error(), "signing key is unknown") {
log.Errorf("callout response signed by unregistered key %s", cr.Issuer)
return nil, ErrAuthorization
} Prevention
- Register every callout signing key as an account signing key (nsc edit account --signing-key)
- Push updated account JWTs to the server after key changes
- Track key rotations and update the account before rotating the callout key
When it happens
Trigger: The AuthorizationResponse carries an Issuer (or IssuerAccount) public key that differs from the target account and is not present in the account's issuer keys (acc.hasIssuer fails).
Common situations: Rotating or adding auth callout signing keys without updating the account's issuer list, using a separate signing key not registered via nsc, or pointing the callout at the wrong account.
Related errors
- auth callout violation: auth callout response is not for exp
- auth callout violation: auth callout response is not for ser
- 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/15f35b034287aeae.
Report an issue: GitHub.