nats-io/nats-server · error
account %q not permitted as valid account option for auth ca
Error message
account %q not permitted as valid account option for auth callout for account %q
What it means
In operator mode, when the user JWT's issuer differs from the expected issuer, the server checks that the issuing account is listed in the target account's allowed_accounts (isAllowedAcount). If not, the callout is not permitted to issue users for that account and the response is rejected.
Source
Thrown at server/auth_callout.go:184
}
// the jwt issuer can be a signing key
jwtIssuer := arc.Issuer
if arc.IssuerAccount != _EMPTY_ {
if !isOperatorMode {
// this should be invalid - effectively it would allow the auth callout
// to issue on another account which may be allowed given the configuration
// where the auth callout account can handle multiple different ones..
return _EMPTY_, fmt.Errorf("error non operator mode account %q: attempted to use issuer_account", account)
}
jwtIssuer = arc.IssuerAccount
}
if jwtIssuer != issuer {
if !isOperatorMode {
return _EMPTY_, fmt.Errorf("wrong issuer for auth callout response on account %q, expected %q got %q", account, issuer, jwtIssuer)
} else if !acc.isAllowedAcount(jwtIssuer) {
return _EMPTY_, fmt.Errorf("account %q not permitted as valid account option for auth callout for account %q",
arc.Issuer, account)
}
}
return jwtIssuer, nil
}
getExpirationAndAllowedConnections := func(arc *jwt.UserClaims, account string) (time.Duration, map[string]struct{}, error) {
allowNow, expiration := validateTimes(arc)
if !allowNow {
c.Errorf("Outside connect times")
return 0, nil, fmt.Errorf("authorized user on account %q outside of valid connect times", account)
}
allowedConnTypes, err := convertAllowedConnectionTypes(arc.User.AllowedConnectionTypes)
if err != nil {
c.Debugf("%v", err)
if len(allowedConnTypes) == 0 {
return 0, nil, fmt.Errorf("authorized user on account %q using invalid connection type", account)View on GitHub (pinned to 3a66a489d2)
Solutions
- Add the issuing account's public key to the target account JWT's allowed_accounts list and re-push the account claim.
- Verify which account signed the user JWT and that it matches an entry in allowed_accounts.
- Ensure the updated account JWT is pushed to the resolver/JS account store so the server reloads it.
Example fix
// before (account JWT)
{ "allowed_accounts": [] }
// after
{ "allowed_accounts": ["ADZJPGQFYly2...issuing-account-pub..."] } Defensive patterns
Strategy: validation
Validate before calling
// before connecting users, confirm the issuing account is permitted: // decode target account JWT and check its allowed_accounts contains the issuer account public key
Prevention
- Keep allowed_accounts in the target account JWT in sync with every callout issuer account.
- Re-push account JWTs after edits and confirm the server picked them up.
- Automate a check that each callout's issuer is in the target account's allowed list.
When it happens
Trigger: Operator-mode deployment; the callout emits a user JWT signed by account X (cr.IssuerAccount/Issuer resolving to X), but X is not in the target account's allowed_accounts list, so acc.isAllowedAcount(jwtIssuer) fails.
Common situations: Adding a new callout/issuing account without adding it to allowed_accounts in the target account JWT; pushing updated account JWTs that dropped an allowed account entry.
Related errors
- operators do not allow authorization callouts to be configur
- error non operator mode account %q: attempted to use issuer_
- authorization response had validation errors: %v
- wrong issuer for auth callout response on account %q, expect
- authorized user on account %q outside of valid connect times
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/54fac325564e0dc5.
Report an issue: GitHub.