{"record":{"id":"8ccf4e6cbcb431e3","repo":"HeyPuter/puter","slug":"unauthorized-8ccf4e","errorCode":"unauthorized","errorMessage":"Authentication required","messagePattern":"Authentication required","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"critical","filePath":"src/backend/drivers/notification/NotificationDriver.ts","lineNumber":210,"sourceCode":"        if (!uid)\n            throw new HttpError(400, 'Missing `uid`', {\n                legacyCode: 'bad_request',\n            });\n        const ok = await this.stores.notification.markAcknowledged(\n            uid,\n            actor.user.id,\n        );\n        return { success: ok };\n    }\n\n    // -- Permissions -------------------------------------------------\n\n    #requireUserActor(): Actor & {\n        user: { id: number; uuid: string; username: string };\n    } {\n        const actor = Context.get('actor') as Actor | undefined;\n        if (!actor)\n            throw new HttpError(401, 'Authentication required', {\n                legacyCode: 'unauthorized',\n            });\n        if (!actor.user?.id)\n            throw new HttpError(403, 'User actor required', {\n                legacyCode: 'forbidden',\n            });\n        // App-under-user actors are not allowed for notifications.\n        if (actor.app)\n            throw new HttpError(403, 'App actors cannot access notifications', {\n                legacyCode: 'forbidden',\n            });\n        return actor as Actor & {\n            user: { id: number; uuid: string; username: string };\n        };\n    }\n\n    // -- Serialization -----------------------------------------------\n","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/notification/NotificationDriver.ts#L192-L228","documentation":"NotificationDriver's #requireUserActor() pulls the actor from Context (ALS); if there is no actor at all, it throws 401 unauthorized. Every notification method runs this first, so an unauthenticated driver/call hits it immediately. This is distinct from the subsequent 403s for missing user or app-actor access.","triggerScenarios":"Calling any puter-notifications method (create/read/select/mark_shown/mark_acknowledged) without an authenticated session in the request context — e.g. a /drivers/call with no or invalid token, or an internal invocation that forgot to set the actor.","commonSituations":"Expired or missing access token; token not attached to the request; calling the driver directly server-side without establishing a Context actor; session timed out in the GUI.","solutions":["Ensure the request carries a valid user access token before calling notification methods.","Re-authenticate / refresh the token if it has expired.","For server-internal callers, set the actor in Context (or use a system token that resolves to one) before invoking the driver."],"exampleFix":"// before — no token on the request\nawait fetch('/drivers/call', { method:'POST', body: JSON.stringify({ interface:'puter-notifications', method:'select' }) });\n\n// after — attach a valid token\nawait fetch('/drivers/call', {\n  method:'POST',\n  headers: { Authorization:`Bearer ${token}` },\n  body: JSON.stringify({ interface:'puter-notifications', method:'select' }),\n});","handlingStrategy":"try-catch","validationCode":"// Ensure a valid token is attached before calling notification methods.\nif (!token) {\n  throw new Error('authentication required for notifications');\n}\nawait callWithAuth(token);","typeGuard":null,"tryCatchPattern":"try {\n  await notifications.select({});\n} catch (e) {\n  if (e.status === 401 && e.code === 'unauthorized') {\n    // session expired — re-authenticate, then retry\n    await reauth();\n  } else throw e;\n}","preventionTips":["Attach a valid user access token to every notification request.","Handle 401 by re-authenticating rather than retrying with the same token.","Notification methods reject app-actor tokens too — use a user token."],"tags":["notifications","authentication","unauthorized","security"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}