Skip to content

Add authentication and room authorization to the backend #15

Description

@naman0r

The backend has no authentication or authorization. It trusts whatever identity the client sends, and does not check whether a caller is allowed to touch a given room.

Clerk runs in the frontend only (apps/web/src/main.tsx). No token ever reaches the backend — there is no JWT verification, no session, no Authorization handling anywhere in apps/backend/app.

This is not a regression from the Python migration. The Spring Boot backend had none either. It was raised during review of #7 and deliberately deferred to its own PR.

Where identity is taken on trust

Site Problem
apps/backend/app/schemas/rooms.py:12 createdBy comes from the request body, so a room can be created as any user
apps/backend/app/schemas/submissions.py:11 userId comes from the request body, so a submission can be attributed to any user
apps/backend/app/main.py:61 userId is a query parameter on /ws/room/{id}, so presence can be claimed as any user
apps/backend/app/main.py:76 /ws/yjs/{room_id} has no check at all — anyone who knows a room id can read and write that room's shared editor document

The Yjs socket is the one that matters most: room ids are UUIDs so they aren't guessable, but there is nothing stopping a client that has one from joining a session it was never invited to.

What needs to happen

  1. Verify a Clerk session token on the backend and derive the user from it, rather than reading an id off the request.
  2. Remove createdBy and userId from request bodies and query strings. They become properties of the authenticated caller.
  3. Authorize room access — check membership before accepting either websocket and before room-scoped reads and writes.
  4. Decide what "allowed in a room" means. There is no concept of invitation or ownership beyond rooms.created_by and the room_members table, and room_members is currently presence, not permission. That distinction needs a decision before any of this can be enforced.

Point 4 is the real design question. The rest follows from it.

Notes

  • Websockets cannot send an Authorization header from the browser. The token has to arrive as a query parameter or as a first message after connect, and be verified before accept(). Worth settling early, since it shapes the whole approach.
  • The frontend already holds a Clerk session, so the client side is mostly a matter of attaching the token.
  • Nothing is deployed yet, so there is no live exposure. This should land before anything is.

Raised in review of #7 (apps/backend/app/schemas/rooms.py).

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestsecurityAuthentication, authorization, data exposure

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions