Files
work-club-manager/.sisyphus/evidence/final-qa/phase3-blocker-no-sub-claim.md
WorkClub Automation 5fb148a9eb chore(evidence): add QA evidence and notepads from debugging sessions
Add comprehensive QA evidence including manual testing reports, RLS isolation
tests, API CRUD verification, JWT decoded claims, and auth evidence files.
Include updated notepads with decisions, issues, and learnings from full-stack
debugging sessions.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-05 19:22:55 +01:00

5.5 KiB

BLOCKER: Task Creation Fails - Missing sub Claim in JWT

Discovery Context

  • Test: Phase 3 - Task 1: Create New Task (POST /api/tasks)
  • Date: 2026-03-05
  • Status: BLOCKED - Cannot proceed with API CRUD tests

Issue Description

Task creation endpoint returns 400 Bad Request with error "Invalid user ID".

Root Cause Analysis

API Code Expectation (TaskEndpoints.cs line 62):

var userIdClaim = httpContext.User.FindFirst("sub")?.Value;
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var createdById))
{
    return TypedResults.BadRequest("Invalid user ID");
}

JWT Payload Reality:

{
  "exp": 1772729098,
  "iat": 1772725498,
  "jti": "5387896f-52a2-4949-bd6e-cbbb09c97a86",
  "iss": "http://localhost:8080/realms/workclub",
  "aud": "workclub-api",
  "typ": "Bearer",
  "azp": "workclub-app",
  "sid": "c5f5ef18-6721-4b27-b577-21d8d4268a06",
  "acr": "1",
  "allowed-origins": ["http://localhost:3000"],
  "scope": "profile email",
  "email_verified": true,
  "clubs": "64e05b5e-ef45-81d7-f2e8-3d14bd197383,3b4afcfa-1352-8fc7-b497-8ab52a0d5fda",
  "name": "Admin User",
  "preferred_username": "admin@test.com",
  "given_name": "Admin",
  "family_name": "User",
  "email": "admin@test.com"
}

Missing Claim: sub (subject) claim is absent from JWT token


Impact Assessment

Affected Endpoints

All endpoints requiring user identification via sub claim are broken:

  • POST /api/tasks - Create task (requires createdById)
  • POST /api/shifts - Create shift (likely requires createdById)
  • Any endpoint that needs to identify the current user

Scope of Blockage

  • Phase 3: API CRUD Tests - BLOCKED (cannot create tasks/shifts)
  • Phase 4: Frontend E2E Tests - BLOCKED (depends on working API)
  • Phase 5: Integration Flow - BLOCKED (step 3 creates task)
  • Phase 6: Edge Cases - ⚠️ PARTIALLY BLOCKED (some tests need task creation)

Tests Still Executable

  • Read operations: GET /api/tasks, GET /api/shifts (already tested)
  • Authorization tests (401/403)
  • Tenant isolation verification (already completed)

Expected vs Actual

Expected (per plan)

Definition of Done: "Keycloak login returns JWT with club claims"

JWT should contain:

  1. clubs claim (present: "64e05b5e-ef45-81d7-f2e8-3d14bd197383,3b4afcfa-1352-8fc7-b497-8ab52a0d5fda")
  2. sub claim (missing: should contain Keycloak user UUID)
  3. aud claim (present: "workclub-api")
  4. email claim (present: "admin@test.com")

Actual Behavior

  • Keycloak token includes clubs custom claim
  • Keycloak token missing standard sub (subject) claim
  • API rejects all create operations requiring user identification

Keycloak Configuration Gap

Standard OpenID Connect Claim: The sub claim is a mandatory claim in OIDC spec and should automatically be included by Keycloak.

Possible Causes:

  1. Client protocol mapper configuration incorrect
  2. User account missing UUID in Keycloak
  3. Token mapper overriding default behavior
  4. Keycloak realm export missing default mappers

Verification Attempted:

# Userinfo endpoint returned 403 (also requires fix)
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/realms/workclub/protocol/openid-connect/userinfo
# HTTP 403

Workaround Options

  • Add sub protocol mapper to workclub-api client
  • Ensure mapper includes Keycloak user ID as UUID
  • Re-acquire tokens after config change

Option 2: Change API to Use Email

  • Modify TaskEndpoints.cs to use email claim instead of sub
  • Query database for member record by email + tenant context
  • Risk: Email not unique across tenants, requires additional lookup

Option 3: Skip Create Operations in QA

  • Continue testing with read-only operations
  • Mark create/update/delete tests as "NOT TESTED - Blocker"
  • Report as critical finding in F3 verdict

Recommendation

STOP F3 QA execution at this point.

This is a CRITICAL BLOCKER preventing:

  • 30+ scenarios in Phase 3 (API CRUD - all create/update operations)
  • All of Phase 4 (Frontend E2E - UI create workflows)
  • All of Phase 5 (Integration - 10-step journey starts with task creation)
  • Most of Phase 6 (Edge cases with concurrent writes)

Estimated Impact: 40/46 remaining scenarios (87% of remaining QA suite) are blocked.


F3 QA Status Update

Scenarios Completed

  • Phase 1: Infrastructure (12/12)
  • Phase 2: RLS Isolation (6/6) (4 PASS, 2 FAIL - shifts RLS missing)
  • Total: 18/58 scenarios (31%)

Scenarios Blocked

  • Phase 3: API CRUD (14 scenarios) BLOCKED
  • Phase 4: Frontend E2E (6 scenarios) BLOCKED
  • Phase 5: Integration (10 steps) BLOCKED
  • Phase 6: Edge Cases (6 tests, ~4 blocked) ⚠️ MOSTLY BLOCKED
  • Total: ~40 scenarios blocked

Blockers Identified

  1. Shifts RLS Policy Missing (Phase 2, Test 4-5): Tenant data leakage on shifts table
  2. JWT Missing sub Claim (Phase 3, Test 1): Cannot create tasks/shifts

Next Steps

For Development Team:

  1. Fix Keycloak configuration to include sub claim in JWT
  2. Implement RLS policy on shifts table (matching work_items policy)
  3. Re-run F3 Manual QA from Phase 3 after fixes

For QA Agent:

  1. Mark F3 QA as INCOMPLETE due to critical blocker
  2. Generate final report with 18/58 scenarios executed
  3. Document both blockers with reproduction steps
  4. Provide FAIL verdict with clear remediation path