critical priority medium complexity backend pending backend specialist Tier 1

Acceptance Criteria

Requests without an Authorization header receive HTTP 401 with body { error: 'missing_authorization' }
Requests with an invalid or expired JWT receive HTTP 401 with body { error: 'invalid_token' }
Requests from authenticated users lacking the integration_admin custom claim receive HTTP 403 with body { error: 'insufficient_permissions' }
Supabase service role key in Authorization header is accepted as a valid caller identity for scheduled invocations from Sync Scheduler
JWT claims are verified using Supabase JWT secret — not trusted from request body
The org_id in the request payload is cross-checked against the organization_id in the JWT claims; mismatch returns HTTP 403 with body { error: 'org_scope_violation' }
Credential lookups (Xledger API key, Dynamics OAuth token) are filtered by the JWT-derived org_id — a query for org A can never return org B credentials even if org B id is passed in payload
All 401/403 responses are logged with: caller_identity (sub claim or 'service_role'), attempted_org_id, rejection_reason, timestamp — without logging the JWT itself
Authentication guard executes before any database read or external API call
Guard function is exported as a standalone middleware callable by any Edge Function in the integration suite

Technical Requirements

frameworks
Supabase Edge Functions (Deno runtime)
Supabase Auth (JWT verification via Supabase JWT secret)
apis
Supabase Auth — JWT decode and verification
Supabase PostgreSQL — credential vault table query scoped by org_id
performance requirements
Auth guard must complete in under 50ms including JWT verification
Credential scope check must use a single indexed query on (org_id, integration_type) — no full table scans
security requirements
JWT secret loaded exclusively from Deno.env — never hardcoded or committed
Service role key must only be accepted from server-side callers — document that mobile clients must never hold this key
integration_admin claim must be verified from JWT app_metadata.claims, not user_metadata (user-writable)
All auth failures must return generic error codes — do not expose whether the token was expired vs malformed vs missing claim (prevents enumeration)
Org scope enforcement must be enforced in code, not solely relying on RLS, to provide defense in depth
Never log full JWT or credential values — only sub claim and org_id

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Integration Task

Handles integration between different epics or system components. Requires coordination across multiple development streams.

Implementation Notes

Implement guard as auth-guard.ts exporting a single async function verifyRequest(req: Request): Promise. If verification fails, return a Response object; if it passes, return an AuthContext containing { userId, orgId, isServiceRole }. Callers check the return type before proceeding. Use Deno's built-in crypto for JWT verification rather than third-party libraries to minimize supply chain risk.

The integration_admin claim lives in app_metadata.claims.integration_admin (set by Supabase admin API) — document this clearly so ops can grant/revoke without code changes. For service role detection, compare the Authorization header value to Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') using a constant-time comparison to prevent timing attacks. All credential vault queries must include AND org_id = $orgId as a WHERE clause parameter — never as a JavaScript filter applied after fetching all rows.

Testing Requirements

Unit tests: (1) missing Authorization header → 401; (2) malformed JWT → 401; (3) valid JWT without integration_admin claim → 403; (4) valid JWT with integration_admin claim for org A trying to invoke for org B → 403 org_scope_violation; (5) service role key → accepted; (6) valid JWT with correct org → guard passes, downstream function called. Use Supabase test JWT signing with known secret for unit tests. Integration test: deploy locally, invoke with real Supabase Auth tokens with and without integration_admin claim, verify response codes. Security test: attempt to pass org_id in payload that differs from JWT claim — verify rejection.

Component
Integration Edge Functions
infrastructure high
Epic Risks (3)
medium impact medium prob technical

Supabase Edge Functions have cold start latency that can cause the first sync invocation after idle periods to fail or timeout when the external API has a short connection window, leading to missed scheduled syncs that go undetected.

Mitigation & Contingency

Mitigation: Configure Edge Function memory and implement a warm-up ping mechanism before heavy sync invocations. Set generous timeout values on the external API calls. Log all cold-start incidents for monitoring.

Contingency: If cold starts cause consistent sync failures, migrate the sync scheduler to a persistent Supabase cron job that pre-warms the function 30 seconds before the scheduled sync time.

high impact low prob technical

The sync scheduler must execute jobs at predictable times for financial reporting accuracy. Drift in cron execution timing (due to Supabase infrastructure delays) could cause syncs to run at wrong times, leading to missing data in accounting exports or duplicate exports across reporting periods.

Mitigation & Contingency

Mitigation: Implement idempotency keys based on integration ID + scheduled period, so re-runs of a delayed sync cannot create duplicate exports. Log actual execution timestamps vs scheduled timestamps and alert on drift exceeding 5 minutes.

Contingency: If scheduler reliability is insufficient, integrate with a dedicated cron service (e.g., pg_cron on Supabase) for millisecond-precise scheduling, replacing the application-level scheduler.

high impact medium prob integration

Aggressive health monitoring ping frequency could trigger rate limiting on external APIs (especially Xledger and Dynamics), causing legitimate export calls to fail after the monitor exhausts the API's request quota.

Mitigation & Contingency

Mitigation: Use lightweight health check endpoints (HEAD requests or vendor-specific ping/status endpoints) rather than data requests. Set health check frequency to once per 15 minutes minimum. Implement exponential backoff after consecutive failures.

Contingency: If rate limiting occurs, disable active health monitoring for the affected integration type and switch to passive health detection (mark unhealthy only when a scheduled sync fails).