Poslední týdny jsem pracoval na integraci Supabase jako externího datového zdroje do platformy Keboola Connection. Vznikl kompletní driver s OAuth 2.0 autentizací, automatickým discovery schémat a napojením přes Supabase Marketplace. Cestou jsem narazil na pár opravdu zákeřných bugů -- tady je celý příběh.
Supabase je open-source alternativa k Firebase postavená nad PostgreSQL. Nabízí autentizaci, real-time subscriptions, storage a především plnohodnotnou PostgreSQL databázi. Keboola je platforma pro datové pipeline, která umožňuje ETL procesy nad různými datovými zdroji.
Cílem bylo umožnit uživatelům připojit svůj Supabase projekt jako externí datový zdroj do Keboola a automaticky z něj číst data pro další zpracování v pipeline.
Původní plán byl CLI příkaz pro manuální registraci OAuth credentials. Jenže testovat kompletní OAuth flow z terminálu je utrpení -- kopírujete URL tam a zpátky, ručně řešíte přesměrování a nemáte žádnou vizuální zpětnou vazbu.
Takže jsem brzy změnil směr: místo CLI nástroje jsem vytvořil webový test harness na /supabase/connect. Jednoduchý formulář, kde zadáte client_id a client_secret, vygeneruje redirect URL z aktuálního hosta, přesměruje vás na Supabase k autorizaci a obslouží callback. Tohle rozhodnutí se ukázalo jako klíčové -- iterativní debugging, který následoval, by z terminálu nebyl možný.
První skutečná výzva přišla z architekury Symfony. Routy označené #[AsPublicAction] běží na stateless firewallu -- žádná session k dispozici. Jenže OAuth flow typicky potřebuje uložit PKCE verifier mezi autorizačním požadavkem a callbackem. Symfony vyhodilo: "Session was used while the request was declared stateless."
Řešení bylo zakódovat všechno -- client credentials, PKCE verifier, redirect URI -- do OAuth state parametru samotného, podepsaného HMAC-SHA256 pomocí kernel.secret. Callback stav dekóduje, ověří podpis a extrahuje PKCE verifier. Kompletně stateless, kompletně bezpečný.
Tento pattern se ukázal jako elegantní: žádná závislost na session, žádné ukládání do databáze, HMAC brání manipulaci a state parametr je z principu validován proti CSRF útokům.
Dvě menší překážky přišly vzápětí:
Záhada approval_prompt. League OAuth2 knihovna přidává approval_prompt do autorizačních požadavků automaticky (konvence Google OAuth). Supabase to odmítlo: "Unrecognized key(s) in object: 'approval_prompt'." Fix: override getAuthorizationParameters() a parametr odfiltrovat.
Projektové vs. účtové OAuth aplikace. Zpočátku jsem vytvořil OAuth aplikaci na úrovni projektu (/project/{ref}/auth/oauth-apps), což vracelo "Unrecognized client_id." Supabase má dva odlišné OAuth scopy -- projektové aplikace a integrační aplikace na úrovni účtu (/account/integrations). Pro marketplace integraci s přístupem napříč projekty je potřeba to druhé.
Tohle byl nejtěžší bug celého projektu. Po vyřešení stateless flow a API záludností stále selhávala výměna kódu za tokeny: "Invalid or expired OAuth authorization."
Zkoušel jsem systematicky:
Accept: application/json header -- stále selhávaloexchangeCodeForTokens() metodu obcházející knihovnu -- stále selhávaloAutorizační flow fungovalo. Callback přijal kód. Ale výměna za tokeny konzistentně vracela tu samou kryptickou chybu.
Průlom: League OAuth2 knihovna má vestavěnou podporu PKCE. Můj kód PKCE taky řešil manuálně kvůli stateless flow. Dvě korektní PKCE implementace běžící současně -- knihovna poslala jeden code_verifier, můj stateless kód poslal jiný. Supabase vidělo nesoulad a výměnu odmítlo.
Fix byl jeden řádek:
protected $pkceMethod = null; // Vypnout vestavěné PKCE knihovny
Klasický integrační bug -- dva nezávisle správné systémy v konfliktu při kombinaci. Debugging zabral hodiny, protože každý jednotlivý dílek vypadal správně.
Driver podporuje dva způsoby, jak se k datům v Supabase dostat:
Přímé PostgreSQL připojení -- klasické databázové připojení přes connection pooler (port 6543). Plný přístup k SQL dotazům, vhodné pro větší objemy dat.
REST API (PostgREST) -- připojení přes Supabase REST endpoint s service_role klíčem. Jednodušší nastavení bez nutnosti sdílet databázové heslo.
Obě varianty podporují šifrované ukládání credentials s oddělenými šifrovacími klíči pro databázové hesla, API klíče a OAuth tokeny.
Po úspěšném OAuth propojení se na pozadí spustí SupabaseProjectSetupJob, který:
ListSchemasCommand na Supabase driverProtobuf komunikace je architektonicky zajímavá -- příkazy se definují ve sdíleném storage-driver-common monorepu a implementují v storage-driver-postgres driveru. Čisté hranice mezi komponentami, žádné přímé provázání.
Uživatel tak po připojení okamžitě vidí svá data v Keboola bez nutnosti ruční konfigurace.
Součástí je klient pro Supabase Management API, který umožňuje:
anon, service_role)Tyto informace se využívají při automatickém nastavení credentials po OAuth flow.
End-to-end zážitek poté, co všechny díly do sebe zapadly:
Celý driver vznikl za jeden týden v přibližně 60 hodinách intenzivní práce s Claude Code. Výsledkem je kolem 25 000 změn -- nové třídy, controllery, migrace, testy, CLI příkazy a dokumentace. Od nuly ke kompletní integraci.
Vývoj probíhal vysoce iterativně: definovat co je potřeba, implementovat, okamžitě otestovat v prohlížeči, debugovat z reálných chybových hlášek. Rychlé feedback smyčky umožnily vyřešit bugy jako PKCE double-handling problém v řádu hodin místo dnů.
AI agent výrazně zrychlil implementaci opakujících se vzorů (controllery, DTO, testy), generování boilerplate kódu a navigaci v rozsáhlém codebase Keboola Connection. Klíčová architektonická rozhodnutí a bezpečnostní model ale samozřejmě vyžadovaly lidský úsudek.
approval_prompt, auth metody, scopy aplikací se liší provider od provideraIntegrace je momentálně ve stavu pull requestu a prochází code review. Těším se, až ji uvidím v produkci.