{"record":{"id":"9f533c353710dab7","repo":"toeverything/AFFiNE","slug":"authentication-required-9f533c","errorCode":"authentication_required","errorMessage":"You must sign in first to access this resource.","messagePattern":"You must sign in first to access this resource\\.","errorType":"exception","errorClass":"AuthenticationRequired","httpStatus":401,"severity":"error","filePath":"packages/backend/server/src/core/user/realtime.ts","lineNumber":24,"sourceCode":"import { z } from 'zod';\n\nimport { AuthenticationRequired, OnEvent, UserNotFound } from '../../base';\nimport { Feature, Models } from '../../models';\nimport { sessionUser } from '../auth/service';\nimport { AvailableUserFeatureConfig } from '../features/types';\nimport { registerRealtimeLiveQuery } from '../realtime/provider';\nimport { RealtimePublisher } from '../realtime/publisher';\nimport { RealtimeRegistry } from '../realtime/registry';\nimport {\n  realtimeUserProfileRoom,\n  realtimeUserSettingsRoom,\n} from '../realtime/rooms';\n\nconst emptyInput = z.object({}).strict();\n\nfunction assertAuthenticated(user?: { id: string }) {\n  if (!user) {\n    throw new AuthenticationRequired();\n  }\n  return user;\n}\n\n@Injectable()\nexport class UserRealtimeProvider\n  extends AvailableUserFeatureConfig\n  implements OnModuleInit\n{\n  constructor(\n    private readonly models: Models,\n    @Optional() private readonly registry?: RealtimeRegistry,\n    @Optional() private readonly publisher?: RealtimePublisher\n  ) {\n    super();\n  }\n\n  onModuleInit() {","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/user/realtime.ts#L6-L42","documentation":"Thrown by assertAuthenticated() in the user realtime provider when the caller is not authenticated. The realtime provider registers live queries for user profile/settings rooms, and both require a valid CurrentUser; passing no user (undefined) trips the guard before any subscription is created.","triggerScenarios":"A realtime subscription request for realtimeUserProfileRoom or realtimeUserSettingsRoom arrives without a valid authenticated session (no user attached by the auth guard).","commonSituations":"Session expired mid-connection; WebSocket connected before login completed; misconfigured guard that lets unauthenticated sockets through to the realtime layer.","solutions":["Ensure the socket is authenticated (token validated) before subscribing to user realtime rooms.","On token expiry, re-authenticate the socket and re-issue the subscription.","Verify the auth guard is wired to the realtime gateway."],"exampleFix":"// before — subscribing before auth confirmed\nsocket.emit('realtime:subscribe', { room: realtimeUserSettingsRoom(userId) });\n\n// after — wait for auth\nawait authenticateSocket(socket);\nsocket.emit('realtime:subscribe', { room: realtimeUserSettingsRoom(userId) });","handlingStrategy":"validation","validationCode":"if (!session?.user) { await authenticate(); return; }\nsubscribe(realtimeUserProfileRoom(session.user.id));","typeGuard":"function isAuthenticated(user?: { id: string }): user is { id: string } {\n  return Boolean(user?.id);\n}","tryCatchPattern":"try {\n  await subscribe(room);\n} catch (e) {\n  if (e?.code === 'authentication_required') { await reauthenticate(); await subscribe(room); return; }\n  throw e;\n}","preventionTips":["Authenticate the socket before subscribing to realtime rooms.","Re-authenticate on token expiry.","Confirm the auth guard is attached to the realtime gateway."],"tags":["user","realtime","auth","websocket"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}