nats-io/nats-server · error

authorized user on account %q outside of valid connect times

Error message

authorized user on account %q outside of valid connect times

What it means

The auth callout's user JWT carries time restrictions (validateTimes), and the connection attempt falls outside the allowed window, so the server refuses to assign the account and rejects the user. This enforces connect-time windows encoded in the user claims returned by the callout.

Source

Thrown at server/auth_callout.go:195

			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)
			}
		}
		return expiration, allowedConnTypes, nil
	}

	assignAccountAndPermissions := func(arc *jwt.UserClaims, account string) (*Account, error) {
		// Apply to this client.
		var err error
		issuerAccount, err := getIssuerAccount(arc, account)
		if err != nil {
			return nil, err

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Re-request authorization so the callout issues a user JWT with a current, valid time window.
  2. Fix clock synchronization (NTP) between the callout service and the NATS server.
  3. Widen the time window in the callout's claim generation for long-running connections.

Example fix

// before
arc.Expires = time.Now().Add(5 * time.Second) // expires almost immediately
// after
arc.Expires = time.Now().Add(30 * time.Minute)
Defensive patterns

Strategy: validation

Validate before calling

vr := jwt.CreateValidationResults()
arc.Validate(vr)
now := time.Now()
if arc.Expires > 0 && now.After(time.Unix(arc.Expires, 0)) {
    return errors.New("user claims expired; request a fresh authorization response")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "outside of valid connect times") {
    // request new credentials from the callout and reconnect
}

Prevention

When it happens

Trigger: The AuthorizationResponseClaims' user JWT has valid from/until style time constraints and validateTimes returns allowNow=false because the current server time is before the start or after the end of the window.

Common situations: Temporary/short-lived user JWTs issued by the callout expiring before a reconnect; clock skew between callout issuer and server making an apparently-valid JWT outside its window.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/92b1148da71c35b7. Report an issue: GitHub.