Workspace Join and Session Participation Flow
This document describes the complete process of joining a workspace and accessing sessions, covering both guest and authenticated user flows.Overview
There are two primary methods for joining a workspace:- Guest Join: Users can join as guests by providing their name and email. They receive a magic link via email to authenticate and access the workspace.
- Authenticated User Join: Existing users can log in with their credentials to join a workspace directly.
Guest Join Flow
The guest join flow allows users to access a workspace without creating a full account. They provide basic information and receive a time-limited magic link via email.Authenticated User Join Flow
Existing users can join a workspace by logging in with their credentials. This provides immediate access without email verification.Magic Link Validation Flow
When a guest user clicks the magic link in their email, the token is validated and exchanged for a JWT token.Session Access
After joining a workspace (via either method), users are redirected to the sessions page. Sessions are filtered based on workspace membership.Workspace Membership
Users gain access to workspace sessions through theuser_workspace junction table:
- Guest users: Added to
user_workspacewhen they join via the guest flow - Regular users: Can be added to workspaces by workspace owners or admins
- Workspace owners: Automatically have access to their own workspaces
Session Filtering
When listing sessions (GET /sessions), the API:
- Verifies the user’s JWT token
- Retrieves workspace IDs from
user_workspacewhere the user is a member - Also includes workspaces where the user is the owner (
workspace.owner_user_id) - Filters sessions to only those belonging to accessible workspaces
Data Model
Users
- Regular users:
is_guest = false, have password hashes, can log in normally - Guest users:
is_guest = true, no password hash, authenticate via magic links - Both types can be members of workspaces via the junction table
Workspaces
- Each workspace has an
owner_user_id(nullable) - Workspaces have a
workspace_type(Private or Shared) - Workspace information is accessible via access codes
User-Workspace Junction Table
Theuser_workspace table links users to workspaces:
user_id: Foreign key to usersworkspace_id: Foreign key to workspacescreated_at,updated_at: Timestamps
Guest Access Tokens
Theguest_access_token table stores magic link tokens:
token: Unique token stringuser_id: Associated guest userworkspace_id: Target workspaceexpires_at: Expiration timestamp (8 hours from creation)accessed_at: Timestamp when token was used (NULL if unused)- Tokens are one-time use (checked via
accessed_at)
Sessions
- Sessions belong to a workspace (
workspace_id) - Users can only access sessions in workspaces they’re members of
- Session access is determined by workspace membership, not direct user-session relationships
API Endpoints
GET /workspaces/:id/public-info?code=...
Validates an access code and returns public workspace information.
Query Parameters:
code: HMAC-based access code (valid for current or previous hour)
400: Invalid workspace ID403: Invalid or expired access code404: Workspace not found
POST /workspaces/:id/join
Creates or finds a guest user and adds them to a workspace. Generates a magic link token and sends it via email.
Request Body:
400: Missing required fields, invalid email, privacy not accepted404: Workspace not found
POST /auth/validate-magic-link
Validates a magic link token and returns a JWT token for authentication.
Request Body:
400: Token is required401: Invalid, expired, or already used token
POST /auth/magic-link
Requests a new magic link for an existing guest user.
Request Body:
400: Invalid workspace ID404: Workspace or guest account not found
GET /workspaces/:id/join-url
Generates a join URL with access code for a workspace. Requires admin authentication.
Response:
Key Points
Access Code Security
- HMAC-based: Access codes are generated using HMAC-SHA256 with the workspace ID and hourly timestamp
- Hourly rotation: Codes are valid for the current hour and the previous hour (grace period)
- Secret key: Uses the JWT secret from configuration
- Format:
HMAC-SHA256(workspace_id:timestamp_hour, secret)encoded as hex
Magic Link Security
- Expiration: Magic links expire 8 hours after creation
- One-time use: Tokens are marked as accessed when used (
accessed_atis set) - Token generation: Uses cryptographically secure random token generation
- Email delivery: Magic links are sent via email with workspace context
Guest User Lifecycle
- Creation: Guest users are created when they first join a workspace
- Reuse: If a guest user with the same email exists, they are reused (not duplicated)
- Workspace membership: Guest users are added to the
user_workspacejunction table - Token management: Old tokens for the same user-workspace pair are deleted when new ones are created
- Disabling: Guest users can be disabled (but not deleted) when removed from workspaces
Session Access Control
- Sessions are filtered by workspace membership
- Users can only see sessions in workspaces they’re members of
- Workspace owners automatically have access to their workspaces
- Admins can access all workspaces and sessions
References
- Backend routes:
crates/api/src/routes/guest_routes.rs,crates/api/src/routes/workspace_routes.rs - Frontend pages:
web/src/routes/join/+page.svelte,web/src/routes/workspaces/[workspaceId]/join/+page.svelte - API utilities:
web/src/lib/api/auth.ts,web/src/lib/api/workspace.ts