Skip to content

Auth: verify Supabase JWTs locally instead of per-request remote lookup #532

Description

@CRamsan

Summary

Back-end ContextRetriever implementations validate every authenticated request with a remote call to Supabase (auth.retrieveUser(token)), putting a network round-trip on the hot path of essentially every API call. We should verify the Supabase JWT locally (signature + exp/iss/aud) and only fall back to a remote lookup when strictly necessary.

Tracks Plan 4 from the back-end auth reassessment: edifikana/docs/04-local-jwt-verification.md (see also edifikana/docs/README.md).

Problem

  • Latency: every request pays a round-trip to the auth provider before any business logic runs.
  • Coupling to provider availability: a Supabase slowdown/outage degrades all authenticated traffic.
  • Cost/throughput: ties request throughput to the auth provider's rate limits.

Affects SupabaseContextRetriever (edifikana) and FlyerBoardContextRetriever (flyerboard), which both call auth.retrieveUser per request.

Proposal

Verify the signed Supabase JWT locally using the project's JWT secret / JWKS:

  • Validate signature, exp, iss, aud without a network call.
  • Build the context payload from token claims (sub -> user id, etc.).
  • Reserve auth.retrieveUser (or a short-TTL cached variant) for cases that genuinely need freshly-fetched user data not present in the token.

Verification options

  1. Symmetric (HS256) secret — validate with the Supabase JWT secret. Simplest; requires securely provisioning the secret.
  2. Asymmetric (JWKS) — fetch and cache the JWKS and verify against rotating public keys. More robust to key rotation; avoids shipping a shared secret.

Acceptance criteria

  • Happy-path authenticated requests perform no remote auth round-trip (verified by test/spy).
  • Signature / expiry / issuer / audience failures are classified as 401 (unauthenticated).
  • Inability to reach the JWKS endpoint (when required) surfaces as 5xx, not 401 (consistent with the Plan 1 outage-vs-401 fix already landed).
  • Secret / JWKS provisioned via existing settings (config.properties.* / SettingsHolder), never hard-coded.
  • Unit tests for valid / expired / wrong-signature / wrong-issuer / wrong-audience tokens.

Risks / notes

  • Secret management: the JWT secret is sensitive; JWKS avoids a shared secret.
  • Claim drift: pin expected claim names; cover with tests.
  • Revocation: local verification cannot see server-side revocation before exp; keep a lightweight cached remote check for sensitive ops if immediate revocation matters.

Full plan: edifikana/docs/04-local-jwt-verification.md

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions