Skip to content

Authentication and Access Control

Sylva uses a combination of custom authentication and Firebase Authentication for user login and session management.

Email/Password Login

  • Users authenticate via the /SystemUsers/Login API endpoint
  • Upon successful login, the system returns a userId and token
  • The system then checks organization access via /SystemUsers/{userId}/checkOrgAccess/{organizationId}
  • If the user has access to the organization, authentication proceeds

Firebase Authentication

  • After successful login, Sylva uses Firebase Authentication for session management
  • Custom tokens are generated via /SystemUsers/{userId}/fbAuthToken/{organizationId}
  • The frontend signs in with the custom token using firebase.auth().signInWithCustomToken()
  • Firebase handles session persistence and token refresh

Email Link Authentication

  • Users can authenticate using email links sent to their email address
  • The system supports password reset via email links

The /SystemUsers/currentUser endpoint provides the current authenticated user’s information:

  • Parameters: Optional _org parameter to specify organization context
  • Response: User object containing:
    • User ID, name, email
    • Roles (system, organization, and course roles)
    • Organization information
    • Access permissions

The current user data is injected into all API requests and stored in the application state.

  • User sessions are managed through Firebase Authentication
  • The current user is fetched on application initialization
  • Organization context (_org) is automatically added to API request headers
  • Session data is stored in the application state and persisted across page reloads

Sylva implements a multi-level role-based access control (RBAC) system with three distinct role levels. While these role levels don’t follow a strict hierarchy, permissions are inherited based on the hierarchical context: System > Organization > Course.

The three role levels are:

  1. System Roles - Applied at the environment level (beta, production, etc.)
  2. Organization Roles - Applied within an organization context
  3. Course Roles - Applied within a specific course/project

System roles are assigned at the environment level and apply across all organizations within that environment.

RoleDescriptionStorage
superadminSpecial role that allows access to the whole environmentMongoDB SystemAccess collection
developerAdds special debugging options to all appsMongoDB SystemAccess collection
sylvauserBase role that all invited users inheritMongoDB SystemAccess collection
creouser (deprecated)Used to allow users to access CREOMongoDB SystemAccess collection

Notes:

  • System roles are assigned separately for each environment (e.g., beta, production, CH, US)
  • Roles are injected into each user via the /currentUser API endpoint
  • Role assignments are stored in a MongoDB collection called SystemAccess

Organization roles control access and permissions within a specific organization.

RoleDescriptionPermissions
adminFull organization accessCan create/delete courses, view/edit all courses in the org, access org settings
moderatorContent management accessCan view/edit all courses
auditorRead-only accessCan view all courses, but cannot access the editor and cannot invite/delete users
creatorLimited creation accessCan create courses but does not have access to other courses except their own

Notes:

  • Organization roles are assigned separately for each environment
  • Roles are injected via the /currentUser API with an _org parameter
  • The _org parameter is automatically added to all API request headers
  • Role assignments are stored in a MongoDB collection called OrganizationAccess

Course roles control access and permissions within a specific course/project.

There are two important “layers” of course/project roles in the frontend:

  • Raw project roles: values coming from backend storage (ProjectAccess) and assigned by invitation/admin UIs.
  • Effective access roles: a normalized set used by route guards and UI logic.

In other words: a user might be assigned the raw role student, but the app will treat them as effective participant.

These are the role values you actually assign at the project level (e.g. from the project People/invitation UI):

Raw roleUI label (typical)Notes
studentParticipantMapped to effective participant
guestParticipant (guest)Mapped to effective guest
contentmanagerStaffCommon “staff” assignment in UI
lecturerStaffStaff category
ownerStaffTypically assigned automatically on create
projectadminStaffStaff category
teachingassistantStaffStaff category
reviewerReviewerReviewer access (not a participant)
graderGraderGrader access (not a participant)

Effective access roles (used for access checks)

Section titled “Effective access roles (used for access checks)”

The frontend normalizes raw project roles to an effective role via CourseRoleMap (session store). These effective roles are what most guards/visibility checks use:

Effective roleMeaning
staffCourse staff / course admin capabilities (depending on route/feature)
participantRegular participant experience
reviewerReviewer experience (restricted participation)
graderGrader experience (restricted participation)
guestGuest participant experience

Raw → effective role mapping (canonical)

Section titled “Raw → effective role mapping (canonical)”

Canonical mapping used by the frontend:

Raw roleEffective role
ownerstaff
projectadminstaff
lecturerstaff
contentmanagerstaff
teachingassistantstaff
gradergrader
reviewerreviewer
studentparticipant
guestguest

Notes:

  • Course roles are assigned separately for each course/project
  • Roles are injected via the /linkedProjects API endpoint
  • Role assignments are stored in a MongoDB collection called ProjectAccess

Dashboard Access (new staff dashboard vs participant dashboard)

Section titled “Dashboard Access (new staff dashboard vs participant dashboard)”

Sylva has two dashboard experiences:

  • New dashboard (“staff dashboard”): designed for staff workflows and quick links.
  • Participant dashboard: the participant-first view (welcome card / start-focused experience).

The app decides which dashboard to show based on organization role and project-level effective role.

New dashboard is shown if any of the following is true:

  • Organization role is one of:
    • admin
    • moderator
    • auditor
    • creator
  • OR the user has at least one linked project where the effective project role is:
    • staff
    • reviewer

Participant dashboard is shown otherwise, i.e. when:

  • the user has no qualifying organization role, and
  • all linked projects map to effective roles in:
    • participant
    • guest
    • grader (graders do not get the staff dashboard)

A previous implementation attempted to infer staff access using a loose rule like “not participant-like ⇒ staff-ish”. That is unsafe because:

  • unknown/legacy/unexpected role strings can appear under project.roles, project.role, or nested access.role fields
  • “not participant” is not equivalent to “staff”

The current logic avoids this by:

  • normalizing raw roles
  • mapping them through the canonical CourseRoleMap
  • making decisions against a small, explicit set of effective roles

All API requests automatically include:

  • Authentication token from the current session
  • Organization context (_org header) when available
  • User role information injected via the /currentUser endpoint

The authentication and access control system is implemented in the Vue.js frontend:

  • Session Store: Manages current user state and authentication status
  • API Interceptors: Automatically add organization context to requests
  • Route Guards: Protect routes based on user roles and permissions
  • Component Guards: Control component visibility and functionality based on roles

Role assignments are stored in MongoDB collections:

  • SystemAccess - System-level role assignments
  • OrganizationAccess - Organization-level role assignments
  • ProjectAccess - Course/project-level role assignments

Each collection links users to their roles within the respective context.