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
- Reactivate the token in settings if revocation was accidental, or
- Issue a new active API token and update every consumer of the old one.
- Centralize the token in a secret manager so rotation updates all clients at once.
- 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
- Use single-source secret injection so revocation propagates everywhere at once.
- Set token expiry and rotate on a schedule instead of long-lived tokens.
- Alert on 401 'revoked' responses to catch stale consumers quickly.
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
- token is invalid
- token not found in database
- token required
- bearer scheme must be used
- token can't be empty
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/4677556ab43d35e6.
Report an issue: GitHub.