Handoff: Auth Crash on Unauthenticated Access + CORS Blocking Port 6200

Two critical bugs preventing gspace1 testing instance from working: blank page crash when not logged in, and CORS rejecting login requests from port 6200

Handoff: Auth Crash + CORS Blocking on Port 6200

From: Testing Director (Cowork agent) To: Coding agents (Cursor/Claude Code) Priority: Critical — blocks all E2E testing on the gspace1 instance Date: 2026-02-06


Context

We're running two instances of the same repo:

Both share the same backend-api on port 3000. The gspace1 instance is completely unusable for testing.


Bug 1: CORS Blocks Login Requests from Port 6200

Problem

The ALLOWED_ORIGINS env var in .env.local is hardcoded to editor2 workspace ports only. Port 6200 is not included, so the backend rejects all API requests from the gspace1 frontend.

Root Cause

File: .env.local (lines ~66-70)

# CORS Configuration - Allow all workspace frontend ports
ALLOWED_ORIGINS=http://localhost:5200,http://localhost:5100,http://localhost:5300,http://localhost:5400,http://localhost:5500,http://localhost:5010,http://localhost:4200

The comment says "all workspace frontend ports" but only lists editor2 ports. The gspace1 ports (6200, 6100, 6300, 6400, 6500) are missing.

How CORS Resolution Works

File: libs/libs-api/backend-core/src/lib/config/cors.factory.ts

At line ~105-116, getAllowedOrigins() checks if ALLOWED_ORIGINS env var is set. If it is, it overrides the dynamic port-based defaults. Since it's set and doesn't include 6200, requests from port 6200 are rejected.

There IS a localhost fallback at line ~152-156 (isLocalhostOrigin()), but the explicit ALLOWED_ORIGINS takes precedence.

Fix

Option A (Quick): Update .env.local to include gspace1 ports:

ALLOWED_ORIGINS=http://localhost:5200,http://localhost:5100,http://localhost:5300,http://localhost:5400,http://localhost:5500,http://localhost:5010,http://localhost:6200,http://localhost:6100,http://localhost:6300,http://localhost:6400,http://localhost:6500,http://localhost:6010,http://localhost:4200,http://localhost:4301

Option B (Better): Remove the ALLOWED_ORIGINS env var entirely and let the buildDefaultOrigins() function at line ~39-52 dynamically build the list from the port env vars (GOGRAB_SPACE_PORT, etc.). This is what it was designed to do.

Option C (Best): Update cors.factory.ts so the isLocalhostOrigin() fallback (line ~152-156) always allows localhost origins in development, even when ALLOWED_ORIGINS is set. This way any localhost port works during development.


Bug 2: App Crashes (Blank Page) When Not Authenticated

Problem

Navigating to http://localhost:6200/space/chrome-space-1/universe/paks-uni-1/hub without being logged in shows a blank page instead of redirecting to the login page. No error message is shown.

Root Cause Chain

The crash is a cascade of silent failures across 4 layers:

Layer 1: authGuard creates ghost users instead of redirecting

File: libs/libs-ui/auth-ui/src/lib/guards/auth.guard.ts (lines ~57-106)

// ALWAYS generate/get guest user for non-authenticated users
let guestUser = await guestAuth.getMostRecentActiveGuestUser();
if (!guestUser) {
  guestUser = await guestAuth.generateTempUser();
}
return true;  // ← ALWAYS returns true, never redirects to /login

The guard was designed for "barrier-free" access. It creates a temporary guest user and always allows navigation. This means there's NO mechanism to redirect to login.

Layer 2: spaceGuard swallows errors

File: libs/libs-foundational/core-angular/src/lib/guards/space.guard.ts

At lines ~198-205, when spaceService.initializeSpace() fails for the guest user:

} catch (error) {
  console.error('[SpaceGuard] Failed to initialize space:', error);
  // Continue - will redirect to landing below if still no space
}

It catches the error, logs it, but returns true anyway (line ~391-393). Navigation continues with no valid space.

Layer 3: spaceResolver returns null

File: libs/libs-foundational/core-angular/src/lib/resolvers/space.resolver.ts (lines ~30-54)

const currentSpace = spaceService.currentSpace();
if (!currentSpace) {
  console.warn('[SpaceResolver] No current space available');
  return null;  // ← Returns null, doesn't redirect or throw
}

Layer 4: Components render with null data → blank page

The route loads successfully (both guards returned true, resolver returned null), but components expect currentSpace to be non-null. They render empty because there's no space context.

Fix

This is an architectural decision. Two approaches:

Option A: Add login redirect (traditional auth) Modify authGuard to redirect to /login when authService.isAuthenticated() is false, instead of creating guest users. Keep guest user creation as a separate opt-in flow.

Option B: Fix the guest flow (maintain barrier-free design) If the barrier-free design is intentional, fix the guest user + space initialization so it actually works:

  1. spaceGuard should create a valid temporary space for guest users
  2. spaceResolver should wait for space init to complete instead of returning null
  3. Add a loading/error state component that shows when space init is in progress or failed

Option C: Add error boundaries (minimum viable fix) At minimum, add a global error handler and error boundary component so the user sees an error message instead of a blank page:

  1. In app.config.ts, add:

    { provide: ErrorHandler, useClass: GlobalErrorHandler }
    
  2. In the main shell component, add a check:

    if (!this.spaceService.currentSpace()) {
      // Show error/redirect to login
    }
    
  3. In spaceResolver, redirect to /landing or /login instead of returning null.

Suggested Approach

I'd recommend Option A + Option C combined: redirect to login when not authenticated AND add error boundaries as a safety net. The guest user creation is a nice feature but it needs a fully working guest space flow to be useful.


Files to Modify

File What to Change
.env.local Add gspace1 ports to ALLOWED_ORIGINS (Bug 1 quick fix)
libs/libs-api/backend-core/src/lib/config/cors.factory.ts Make localhost always allowed in dev (Bug 1 proper fix)
libs/libs-ui/auth-ui/src/lib/guards/auth.guard.ts Add login redirect for unauthenticated users (Bug 2)
libs/libs-foundational/core-angular/src/lib/guards/space.guard.ts Return false + redirect when space init fails (Bug 2)
libs/libs-foundational/core-angular/src/lib/resolvers/space.resolver.ts Redirect instead of returning null (Bug 2)
apps/gograb-space/src/app/app.config.ts Add global ErrorHandler (Bug 2 safety net)

Verification Steps

After the fix, I (Testing Director) will verify:

  1. Navigate to http://localhost:6200/login → login page should render
  2. Enter credentials → login should succeed (no CORS error in network tab)
  3. After login → should redirect to space dashboard
  4. Navigate to http://localhost:6200/space/chrome-space-1/universe/paks-uni-1/hub when NOT logged in → should redirect to login (not blank page)
  5. Navigate to http://localhost:6200/space/chrome-space-1/universe/paks-uni-1/hub when logged in → hub should render properly
  6. Check browser console → no unhandled errors

Quick Win (Do This First)

The fastest way to unblock testing is to update .env.local:

- ALLOWED_ORIGINS=http://localhost:5200,http://localhost:5100,http://localhost:5300,http://localhost:5400,http://localhost:5500,http://localhost:5010,http://localhost:4200
+ ALLOWED_ORIGINS=http://localhost:5200,http://localhost:5100,http://localhost:5300,http://localhost:5400,http://localhost:5500,http://localhost:5010,http://localhost:6200,http://localhost:6100,http://localhost:6300,http://localhost:6400,http://localhost:6500,http://localhost:6010,http://localhost:4200,http://localhost:4301

Then restart backend-api so it picks up the new env. This won't fix the blank page crash (Bug 2) but will at least allow login to work if you navigate directly to /login.