{"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/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/core/user/realtime.ts#L6-L42","documentation":"The user realtime provider backs live queries over the user's profile and settings rooms. Its helpers call assertAuthenticated, which throws authentication_required when the current user object is missing - i.e. the socket/request is anonymous (never signed in, session expired, or token not attached).","triggerScenarios":"Subscribing to realtime user profile/settings rooms before sign-in completes; a session that expired or was revoked while the socket stayed connected; auth middleware failing to attach the user so the realtime path sees undefined.","commonSituations":"Frontend booting realtime subscriptions during the auth handshake; long-lived sockets surviving past token expiry; tokens invalidated by sign-out-everywhere.","solutions":["Wait for a successful sign-in (session resolved) before subscribing to realtime user events","On this error, re-authenticate, then reconnect and resubscribe","Gate realtime subscription setup behind your auth-state store"],"exampleFix":"// before\nregistry.subscribe('user:profile', handler); // anonymous socket throws\n\n// after\nif (isAuthenticated(user)) {\n  registry.subscribe('user:profile', handler);\n}","handlingStrategy":"validation","validationCode":"// subscribe only when a session is present\nif (!session.user) {\n  throw new Error('sign in before subscribing to realtime user events');\n}\nawait subscribeUserRealtime(session.user.id);","typeGuard":"function isAuthenticated(user?: { id: string } | null): user is { id: string } {\n  return !!user?.id;\n}","tryCatchPattern":"try {\n  await subscribeUserRealtime(userId);\n} catch (e) {\n  if (e?.code === 'authentication_required') {\n    await reauthenticate();\n    await subscribeUserRealtime(userId);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Gate realtime subscriptions behind the auth-state store, not the page lifecycle","Handle token expiry on long-lived sockets by re-authenticating and resubscribing","Do not attempt anonymous realtime subscriptions - the provider requires a user by design"],"tags":["authentication","realtime","websocket","session"],"backgroundTag":"authentication-required","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}