vxcontrol/pentagi · error

token has been revoked

Error message

token has been revoked

What it means

The token is valid and exists in the database, but its stored status is not TokenStatusActive, so the middleware rejects the request. Revocation (or any non-active lifecycle state) intentionally disables the credential; the JWT signature alone is not sufficient.

Source

Thrown at backend/pkg/server/auth/auth_middleware.go:230

		return authResultSkip, errors.New("token validation disabled with default salt")
	}

	// try to validate as API token first (new format with JWT signing key)
	apiClaims, apiErr := ValidateAPIToken(token, p.globalSalt)
	if apiErr != nil {
		return authResultFail, errors.New("token is invalid")
	}

	// check token status and get privileges through cache
	status, privileges, err := p.tokenCache.GetStatus(apiClaims.TokenID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return authResultFail, errors.New("token not found in database")
		}
		return authResultFail, fmt.Errorf("error checking token status: %w", err)
	}
	if status != models.TokenStatusActive {
		return authResultFail, errors.New("token has been revoked")
	}

	// Verify user hash matches database
	dbHash, userStatus, err := p.userCache.GetUserHash(apiClaims.UID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return authResultFail, errors.New("user has been deleted")
		}
		return authResultFail, fmt.Errorf("error checking user status: %w", err)
	}

	if userStatus == models.UserStatusBlocked {
		return authResultFail, errors.New("user has been blocked")
	}

	if dbHash != apiClaims.UHASH {
		return authResultFail, fmt.Errorf("%w - token invalid for this installation", errUserHashMismatch)
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Reactivate the token in settings if revocation was accidental, or
  2. Issue a new active API token and update every consumer of the old one.
  3. Centralize the token in a secret manager so rotation updates all clients at once.
  4. Remove tokens belonging to offboarded users from scripts and CI variables.

Example fix

# before (CI secret)
API_TOKEN: tok_revoked_123

# after
API_TOKEN: tok_new_active_456  # reissued after revocation of tok_revoked_123
Defensive patterns

Strategy: retry

Validate before calling

# pre-check token status before use:
# SELECT status FROM api_tokens WHERE token_id = '<id>';  -- must be 'active'

Try / catch

try {
  return await call(token);
} catch (e) {
  if (is401(e) && /revoked/i.test(e.message)) {
    const replacement = await rotateCredential(); // do NOT blind-retry with same token
    return await call(replacement);
  }
  throw e;
}

Prevention

When it happens

Trigger: Using an API token after it was revoked/deactivated in the settings UI; a token disabled by an administrator during an incident; automation jobs still running with tokens revoked during offboarding.

Common situations: Credential rotation where the old token was revoked but not all consumers were updated; security incident response revoking shared tokens; team member departure with their token embedded in scripts.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/4677556ab43d35e6. Report an issue: GitHub.