LiveBoard / docsProject documentation

Reference

Access Control, Sessions, and Removal

Look up syntax, contracts, layouts, algorithms, and exact behavior.

Sharing modal. The share modal exposes the membership set and lets the owner add or remove access without leaving the editor.

Canvas access is a graph edge from user to canvas, plus ownership. The owner is implicit from the canvas row. Shared access is stored in a membership table. A user may open a canvas if they are the owner or a current member.

The application bootstrap starts with the same security model. On load, the React app calls GET /api/me with same-origin credentials. If the liveboard_session cookie maps to a valid server-side session, the dashboard opens. If not, the user sees signup/login. Signup normalizes credentials, hashes the password, creates a session, and sets the httpOnly cookie. Login accepts username or email, verifies the stored password hash, and creates the same session shape.

Access control is enforced on both ordinary HTTP routes and the WebSocket path. That is necessary because a collaborative editor has two doors into the same resource: a user can fetch the canvas over HTTP, or they can join the live editing room. The same predicate has to guard both doors, and it has to remain true after the socket has already opened.

canOpen(u,c)=owner(c)=u∨(u,c)∈AcanOpen(u,c) = owner(c)=u \lor (u,c) \in A
Access predicate. Both HTTP reads and WebSocket joins evaluate the same ownership-or-membership predicate.

Session tokens are stored server-side, expire automatically, and are rechecked while WebSockets are open. Deleting a stolen token eventually stops an attacker even if they already established a socket. Membership removal also closes active sockets for the removed user and displays an access message on their screen.

owner opens share modal
  -> GET /api/canvases/:id/members
  -> owner enters username or email
  -> POST /api/canvases/:id/invite
  -> backend verifies owner and target user
  -> INSERT canvas_members
  -> modal updates member list
  -> invited user sees canvas in Shared with You
Invite flow. Sharing is stored as membership rows. Folders remain owner-local and do not affect whether the invited user can open the canvas.
owner removes member
  -> DELETE /api/canvases/:id/members/:userId
  -> database membership row deleted
  -> Redis invalidation reaches every backend replica
  -> each room manager finds matching local sockets
  -> access_removed message
  -> socket close
  -> removed client stops receiving updates
Removal path. Access changes affect both future authorization and currently connected editors.

The Redis invalidation path is an acceleration path, not the security boundary. Open sockets re-check their session and canvas membership before every incoming message and every 30 seconds while idle. If an invalidation message is missed, the next database-backed check still closes an unauthorized socket.

Canvas rename is intentionally split by ownership and context. Owners can rename from the dashboard context menu or inline from the board header; both use PATCH /api/canvases/{canvas_id}. Connected editors receive a canvas_renamed WebSocket event so the open header stays in sync. Non-owners can open shared canvases but cannot rename them or move them through the owner's folder tree.