{"record":{"id":"480265467db1377f","repo":"Mintplex-Labs/anything-llm","slug":"unauthorized-480265","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"server/endpoints/browserExtension.js","lineNumber":209,"sourceCode":"      }\n    }\n  );\n\n  app.delete(\n    \"/browser-extension/api-keys/:id\",\n    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],\n    async (request, response) => {\n      try {\n        const { id } = request.params;\n        const user = await userFromSession(request, response);\n\n        if (multiUserMode(response) && user.role !== ROLES.admin) {\n          const apiKey = await BrowserExtensionApiKey.get({\n            id: parseInt(id),\n            user_id: user?.id,\n          });\n          if (!apiKey) {\n            return response.status(403).json({ error: \"Unauthorized\" });\n          }\n        }\n\n        const { success, error } = await BrowserExtensionApiKey.delete(id);\n        if (!success) throw new Error(error);\n        response.status(200).json({ success: true });\n      } catch (error) {\n        console.error(error);\n        response.status(500).json({ error: \"Failed to revoke API key\" });\n      }\n    }\n  );\n}\n\nmodule.exports = { browserExtensionEndpoints };\n","sourceCodeStart":191,"sourceCodeEnd":225,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/browserExtension.js#L191-L225","documentation":"Deliberate 403 from DELETE /browser-extension/api-keys/:id. In multi-user mode, a non-admin (manager) may only delete keys they own: the code looks the key up by { id, user_id } and a null result means 'no such key owned by you', refusing with Unauthorized. Admins skip the ownership check entirely and can delete any key.","triggerScenarios":"A manager calling DELETE on a key created by another user; the key was already deleted so the scoped lookup misses; passing the wrong id (or the key string instead of the numeric id), which parseInt turns into NaN so no row ever matches.","commonSituations":"Multi-admin teams with per-user extension keys; stale key list in the admin UI after someone else revoked a key.","solutions":["Refresh GET /browser-extension/api-keys and delete using the numeric id of a key your own user created.","If the key belongs to another user, ask an admin to perform the delete.","Confirm you are sending the numeric id in the URL, not the API key string."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const myRole = await currentUserRole();\nconst keys = await listExtensionApiKeys();\nconst owned = keys.find((k) => String(k.id) === String(id));\nif (myRole !== 'admin' && !owned) throw new Error('This key is not yours to revoke - ask an admin');","typeGuard":"const isNumericId = (v: unknown): v is string | number =>\n  (typeof v === 'string' && /^\\d+$/.test(v)) || typeof v === 'number';","tryCatchPattern":"try { await revokeKey(id); }\ncatch (e) {\n  if (e.status === 403) { /* refresh the key list; the id is gone or not owned by you */ }\n  else throw e;\n}","preventionTips":["Refresh the key list immediately before revoking.","Send the numeric id, never the key string.","As a manager, only attempt to revoke keys your user created."],"tags":["api-keys","http-403","permissions","multi-user","browser-extension"],"backgroundTag":"permission-denied","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}