Skip to main content

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:
  1. 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.
  2. Authenticated User Join: Existing users can log in with their credentials to join a workspace directly.
Both methods require a valid access code that is generated using HMAC-SHA256 and rotates hourly.

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. 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 the user_workspace junction table:
  • Guest users: Added to user_workspace when 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:
  1. Verifies the user’s JWT token
  2. Retrieves workspace IDs from user_workspace where the user is a member
  3. Also includes workspaces where the user is the owner (workspace.owner_user_id)
  4. 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

The user_workspace table links users to workspaces:
  • user_id: Foreign key to users
  • workspace_id: Foreign key to workspaces
  • created_at, updated_at: Timestamps

Guest Access Tokens

The guest_access_token table stores magic link tokens:
  • token: Unique token string
  • user_id: Associated guest user
  • workspace_id: Target workspace
  • expires_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)
Response:
Errors:
  • 400: Invalid workspace ID
  • 403: Invalid or expired access code
  • 404: 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:
Response:
Errors:
  • 400: Missing required fields, invalid email, privacy not accepted
  • 404: Workspace not found

POST /auth/validate-magic-link

Validates a magic link token and returns a JWT token for authentication. Request Body:
Response:
Errors:
  • 400: Token is required
  • 401: Invalid, expired, or already used token

POST /auth/magic-link

Requests a new magic link for an existing guest user. Request Body:
Response:
Errors:
  • 400: Invalid workspace ID
  • 404: 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
  • Expiration: Magic links expire 8 hours after creation
  • One-time use: Tokens are marked as accessed when used (accessed_at is set)
  • Token generation: Uses cryptographically secure random token generation
  • Email delivery: Magic links are sent via email with workspace context

Guest User Lifecycle

  1. Creation: Guest users are created when they first join a workspace
  2. Reuse: If a guest user with the same email exists, they are reused (not duplicated)
  3. Workspace membership: Guest users are added to the user_workspace junction table
  4. Token management: Old tokens for the same user-workspace pair are deleted when new ones are created
  5. 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