{"record":{"id":"4677556ab43d35e6","repo":"vxcontrol/pentagi","slug":"token-has-been-revoked","errorCode":null,"errorMessage":"token has been revoked","messagePattern":"token has been revoked","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"backend/pkg/server/auth/auth_middleware.go","lineNumber":230,"sourceCode":"\t\treturn authResultSkip, errors.New(\"token validation disabled with default salt\")\n\t}\n\n\t// try to validate as API token first (new format with JWT signing key)\n\tapiClaims, apiErr := ValidateAPIToken(token, p.globalSalt)\n\tif apiErr != nil {\n\t\treturn authResultFail, errors.New(\"token is invalid\")\n\t}\n\n\t// check token status and get privileges through cache\n\tstatus, privileges, err := p.tokenCache.GetStatus(apiClaims.TokenID)\n\tif err != nil {\n\t\tif errors.Is(err, gorm.ErrRecordNotFound) {\n\t\t\treturn authResultFail, errors.New(\"token not found in database\")\n\t\t}\n\t\treturn authResultFail, fmt.Errorf(\"error checking token status: %w\", err)\n\t}\n\tif status != models.TokenStatusActive {\n\t\treturn authResultFail, errors.New(\"token has been revoked\")\n\t}\n\n\t// Verify user hash matches database\n\tdbHash, userStatus, err := p.userCache.GetUserHash(apiClaims.UID)\n\tif err != nil {\n\t\tif errors.Is(err, gorm.ErrRecordNotFound) {\n\t\t\treturn authResultFail, errors.New(\"user has been deleted\")\n\t\t}\n\t\treturn authResultFail, fmt.Errorf(\"error checking user status: %w\", err)\n\t}\n\n\tif userStatus == models.UserStatusBlocked {\n\t\treturn authResultFail, errors.New(\"user has been blocked\")\n\t}\n\n\tif dbHash != apiClaims.UHASH {\n\t\treturn authResultFail, fmt.Errorf(\"%w - token invalid for this installation\", errUserHashMismatch)\n\t}","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/auth/auth_middleware.go#L212-L248","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (CI secret)\nAPI_TOKEN: tok_revoked_123\n\n# after\nAPI_TOKEN: tok_new_active_456  # reissued after revocation of tok_revoked_123","handlingStrategy":"retry","validationCode":"# pre-check token status before use:\n# SELECT status FROM api_tokens WHERE token_id = '<id>';  -- must be 'active'","typeGuard":null,"tryCatchPattern":"try {\n  return await call(token);\n} catch (e) {\n  if (is401(e) && /revoked/i.test(e.message)) {\n    const replacement = await rotateCredential(); // do NOT blind-retry with same token\n    return await call(replacement);\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["authentication","api-token","go","revocation"],"backgroundTag":"token-revoked","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}