feat(auth): add server-controlled student and admin sessions

Replaces the Phase 2A pilot ?sid= query param with an HttpOnly,
SameSite=Lax session cookie. Gateway now derives student identity from
the session (via Platform API's /api/session/whoami) instead of trusting
a client-suppliable id, and checks ownership on every proxied HTTP and
WebSocket Lab request, not just the initial navigation.

Fixes a routing bug found during testing: the fallback route was using
'does this session own a running environment' to decide whether an
unprefixed /api/* call belonged to the Lab UI or the dashboard — true in
both places. Replaced with an explicit LAB_OWNED_PATHS allowlist of the
exact unprefixed paths the existing Lab UI actually calls.

e2e-phase2a.js rewritten to use a cookie jar instead of headers/query
params, with explicit impersonation-rejection tests added. 10/10 passing.
This commit is contained in:
2026-08-18 12:22:58 -05:00
parent 6b52c9e1d2
commit ae75bb4cbe
6 changed files with 257 additions and 294 deletions
+1 -2
View File
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'
import { api, storeStudent } from './api'
import { api } from './api'
import styles from './Platform.module.css'
// A. Entry screen — RootNode Academy branding, choose your name from roster, no password.
@@ -28,7 +28,6 @@ export default function EntryScreen({ onLogin }) {
setError(null)
try {
const student = await api.login(studentId)
storeStudent(student)
onLogin(student)
} catch (e) {
setError(e.message)