Files
nas-runbooks/common/baserow-mcp-oauth-fix.md
T

5.0 KiB

baserow-mcp-oauth-fix — sidecar OAuth devant Baserow (28/07/2026)

Statut : deploye, teste bout-en-bout. Reste 1 action manuelle (voir "Action restante").

Probleme

Connecteur Claude.ai vers Baserow MCP (https://baserow.bolbol.tn/mcp/<token>/sse) : « Impossible de s'inscrire aupres du service de connexion de Baserow ».

Cause : meme piege que mcp-vps.md/mcp-nas — Claude.ai sonde systematiquement /.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource et POST /register a l'ajout d'un connecteur MCP personnalise, meme quand le serveur cible n'a besoin d'aucune auth (la vraie protection Baserow = le token secret deja dans l'URL /mcp/<token>/sse). Baserow (Caddy + Nuxt) renvoie 404 (page Nuxt generique, pas une 404 backend) sur ces 3 routes → echec du handshake connecteur.

Difference avec mcp-vps/mcp-nas : ceux-la sont du code Python maison, patchable directement. Baserow est l'image officielle (watchtower la met a jour) — impossible de patcher son code source sans que ca saute au prochain rebuild/update.

Fix

Sidecar devant Baserow, sans toucher a l'image Baserow : /volume1/docker/baserow-oauth-stub (2 containers, reseau n8n uniquement) :

  • baserow-oauth-app (Starlette/uvicorn, build local, pas de port publie) : /register, /authorize, /token — meme pattern PKCE que linux_mcp_server.py (mcp-vps), CLIENT_ID = claude-baserow-mcp, tokens jamais verifies ailleurs (la seule vraie protection reste le token dans l'URL Baserow).
  • baserow-oauth-proxy (nginx:alpine, port 3887→80, reseau n8n) :
    • /.well-known/oauth-authorization-server et /.well-known/oauth-protected-resource(/*) → JSON statique (fichiers montes en volume, pas de logique dynamique necessaire)
    • /register, /authorize, /token → proxy vers baserow-oauth-app:8080
    • location / (tout le reste : app web, API, /ws/*, /mcp/*/sse) → proxy transparent vers baserow:80 (alias Docker du container Baserow sur le reseau n8n), avec support WebSocket (map $http_upgrade $connection_upgrade) et SSE (proxy_buffering off, proxy_read_timeout 3600s, chunked_transfer_encoding on).

Gotcha reseau (couteux a redecouvrir)

Premiere tentative : 2 services sur un reseau default cree par le compose (nouveau bridge custom) + le service nginx en plus sur n8n. Resultat : ping fonctionne entre les 2 containers, mais toute connexion TCP (nc, wget, proxy_pass) time out en silence (502/504 selon le point de test) — alors que Baserow lui-meme (deja sur n8n) passait sans probleme. Hypothese : regle firewall (crowdsec-firewall-bouncer ou iptables DOCKER-USER) qui n'autorise le trafic TCP inter-conteneurs que sur les reseaux Docker deja connus/etablis (n8n), pas sur un reseau tout juste cree. Fix : mettre les 2 services UNIQUEMENT sur le reseau externe n8n (pas de reseau default supplementaire) — resout immediatement le probleme, ping ET TCP passent. A retenir pour tout futur sidecar : privilegier un reseau externe deja peuple plutot qu'un nouveau bridge, si un blocage TCP-mais-pas-ICMP apparait entre 2 conteneurs.

Tests de validation (28/07/2026)

Tous compares en baseline (direct port 3888, bypass total du sidecar) vs via le proxy (port 3887) :

Test Baseline 3888 Via proxy 3887
/.well-known/oauth-authorization-server 404 (Baserow) 200 JSON statique
/.well-known/oauth-protected-resource 404 (Baserow) 200 JSON statique
POST /register 404 (Baserow) 201, client_id: claude-baserow-mcp
GET /authorize + PKCE S256 → POST /token n/a 200, access_token + refresh_token
GET /mcp/<token>/sse (bon Host header) 200, event endpoint 200, event endpoint identique
GET / (app web) 302 (redirect login) 302 identique
GET /api/_health/ 200 200 identique
Upgrade WebSocket /ws/core/ 101 Switching Protocols 101 identique

Piege methodologique note en passant : tester /mcp/<token>/sse en curl direct sur le port 3888 SANS forcer Host: baserow.bolbol.tn renvoie un faux-negatif (404 JSON generique Nuxt) — le Caddyfile de Baserow route /api/* /ws/* /mcp/* /assistant/* vers le backend uniquement si l'expression @is_baserow_tool matche BASEROW_PUBLIC_URL sur le Host recu ; sinon fallback silencieux vers le frontend Nuxt qui 404 proprement. Toujours forcer le bon Host en test local.

Action restante (manuelle, root DSM — meme pattern que cin.bolbol.tn/formation.bolbol.tn)

Reverse-proxy DSM baserow.bolbol.tn : changer la destination 3888 → 3887. Seul geste necessaire ; reversible en 10 secondes (remettre 3888) si probleme. Apres bascule : reconnecter le connecteur Baserow dans claude.ai (Parametres → Connecteurs) pour relancer le handshake OAuth avec les nouveaux endpoints.

Fichiers

/volume1/docker/baserow-oauth-stub/ : oauth_app.py, Dockerfile, nginx.conf, oauth-authorization-server.json, oauth-protected-resource.json, docker-compose.yml (miroir complet pousse dans ce commit, sous common/baserow-oauth-stub/).