# 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
