Files
work-club-manager/.sisyphus/evidence/final-qa/phase3-blocker-no-sub-claim.md

177 lines
5.5 KiB
Markdown
Raw Permalink Normal View History

# 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):
```csharp
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**:
```json
{
"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**:
```bash
# 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
### Option 1: Fix Keycloak Configuration (RECOMMENDED)
- 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