Poslední týdny jsem dělal na integraci Supabase do Keboola Connection. Vznikl z toho kompletní driver s OAuth 2.0, automatickým discovery schémat a napojením na Supabase Marketplace. A cestou jsem narazil na pár bugů, ze kterých jsem málem šedivěl.
Supabase je open-source alternativa k Firebase postavená nad PostgreSQL -- autentizace, real-time, storage a hlavně plnohodnotná PostgreSQL databáze. Keboola je platforma pro datové pipeline a ETL procesy nad různými datovými zdroji.
Cíl byl jednoduchý: uživatel připojí svůj Supabase projekt jako externí datový zdroj v Keboola a data se automaticky začnou stahovat do pipeline.
Původně jsem chtěl CLI příkaz na registraci OAuth credentials. Jenže testovat OAuth flow z terminálu je utrpení -- kopírujete URL tam a zpátky, ručně řešíte přesměrování, žádná vizuální zpětná vazba.
Takže jsem brzo otočil: místo CLI jsem postavil webový test harness na /supabase/connect. Jednoduchý formulář, zadáte client_id a client_secret, vygeneruje redirect URL, pošle vás na Supabase a obslouží callback. Tohle rozhodnutí se ukázalo jako klíčové -- iterativní debugging, který následoval, by z terminálu prostě nešel.
První pořádná výzva přišla ze Symfony. Routy s #[AsPublicAction] běží na stateless firewallu -- žádná session. Jenže OAuth flow typicky potřebuje uložit PKCE verifier mezi autorizací a callbackem. Symfony vyhodilo: "Session was used while the request was declared stateless."
No a co s tím? Zakódovat všechno -- client credentials, PKCE verifier, redirect URI -- přímo do OAuth state parametru, podepsaného HMAC-SHA256 přes kernel.secret. Callback stav dekóduje, ověří podpis a vytáhne PKCE verifier. Žádná session, žádná databáze, HMAC brání manipulaci a state parametr z principu chrání proti CSRF. Elegantní.
Pak přišly dvě menší překážky:
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'." Stačilo přepsat getAuthorizationParameters() a parametr odfiltrovat.
Projektové vs. účtové OAuth aplikace. Vytvořil jsem OAuth aplikaci na úrovni projektu (/project/{ref}/auth/oauth-apps) a dostával "Unrecognized client_id." Supabase má totiž dva odlišné scopy -- projektové aplikace a integrační aplikace na úrovni účtu (/account/integrations). Pro marketplace integraci přes projekty potřebujete to druhé. Tohle v dokumentaci snadno přehlédnete.
Tohle byl nejtěžší bug celého projektu. Po vyřešení stateless flow a API záludností pořád selhávala výměna kódu za tokeny: "Invalid or expired OAuth authorization."
Zkoušel jsem systematicky:
Accept: application/json header -- pořád nicexchangeCodeForTokens() obcházející knihovnu -- pořád nicAutorizace fungovala. Callback dostal kód. Ale výměna za tokeny konzistentně vracela tu samou kryptickou chybu. Šílel jsem z toho.
Průlom: League OAuth2 knihovna má vestavěnou PKCE podporu. Můj kód PKCE taky řešil manuálně kvůli stateless flow. Dvě korektní PKCE implementace běžely současně -- knihovna poslala jeden code_verifier, můj kód jiný. Supabase vidělo nesoulad a výměnu odmítlo.
Fix? Jeden řádek:
protected $pkceMethod = null; // Vypnout vestavěné PKCE knihovny
Klasický integrační bug -- dva systémy, každý sám o sobě správný, v kombinaci nefungují. Debugging zabral hodiny, protože každý dílek zvlášť vypadal v pohodě.
Driver podporuje dva způsoby přístupu k datům:
Přímé PostgreSQL připojení -- klasika přes connection pooler (port 6543). Plný přístup k SQL, vhodné pro větší objemy dat.
REST API (PostgREST) -- přes Supabase REST endpoint s service_role klíčem. Jednodušší setup bez sdílení databázového hesla.
Obě varianty podporují šifrované ukládání credentials s oddělenými klíči pro hesla, API klíče a OAuth tokeny.
Po úspěšném OAuth propojení se na pozadí spustí SupabaseProjectSetupJob:
ListSchemasCommand na Supabase driverProtobuf komunikace je architektonicky fajn -- příkazy se definují ve sdíleném storage-driver-common monorepu a implementují v storage-driver-postgres driveru. Čisté hranice, žádné přímé provázání.
Uživatel po připojení okamžitě vidí svá data bez jakékoli ruční konfigurace.
Součástí je klient pro Supabase Management API:
anon, service_role)Tahle data se využívají při automatickém nastavení credentials po OAuth flow.
Jak to vypadá end-to-end:
Celý driver vznikl za týden v asi 60 hodinách intenzivní práce s Claude Code. Výsledek je kolem 25 000 změn -- třídy, controllery, migrace, testy, CLI příkazy, dokumentace. Od nuly ke kompletní integraci.
Vývoj probíhal vysoce iterativně: definovat co je potřeba, implementovat, hned otestovat v prohlížeči, debugovat z reálných chybovek. Rychlé feedback smyčky umožnily vyřešit i PKCE double-handling v řádu hodin místo dnů.
AI agent výrazně zrychlil opakující se vzory (controllery, DTO, testy), generování boilerplate a navigaci v rozsáhlém Keboola codebase. Klíčová architektonická rozhodnutí a bezpečnostní model ale samozřejmě vyžadovaly lidský úsudek.
approval_prompt, auth metody, scopy aplikací, nic není standardIntegrace je momentálně v pull requestu a prochází code review. Těším se, až to poběží v produkci.