Service account pattern resolves 401 PERMISSION_DENIED on Baserow metadata endpoints (/api/database/views/table/:id/, /api/database/tables/:id/) which reject DB tokens. A dedicated Baserow user account logs in via token-auth, JWT cached in memory with mutex-protected refresh before expiry. Fallback graceful: if BASEROW_USER_EMAIL/PASSWORD absent, CRUD rows still work, metadata endpoints return 500 BASEROW_USER_AUTH_NOT_CONFIGURED. 417 tests pass (was 392, +25). 0 TS errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.4 KiB
Baserow Authentication — Bridge Service
Pourquoi deux types de tokens
Baserow expose deux mecanismes d'authentification aux comportements differents :
| Type | Header | Droits | Usages |
|---|---|---|---|
| DB token | Token brg_* |
CRUD rows uniquement | listRows, createRow, updateRow, deleteRow |
| User JWT | JWT eyJ... |
Toutes les routes API | Metadata : listViews, getTable, resolveTableIds |
Le DB token (BASEROW_API_TOKEN) est suffisant pour 90% des cas mais Baserow renvoie
401 PERMISSION_DENIED sur les endpoints metadata. Ce n'est pas un bug : c'est la
conception Baserow qui distingue DB tokens (CRUD rows) des user sessions (lecture
full-API).
Le bridge utilise donc les deux :
- DB token : routes
/api/database/rows/table/:id/— toujours actif - User JWT : routes
/api/database/views/table/:id/,/api/database/tables/:id/— actif siBASEROW_USER_EMAIL+BASEROW_USER_PASSWORDsont configures
API Baserow — endpoints JWT
Source : docs.baserow.io + github.com/code-watch/baserow/blob/master/docs/getting-started/api.md
Login
POST /api/user/token-auth/
Content-Type: application/json
{ "username": "email@example.com", "password": "..." }
Reponse :
{ "token": "eyJ..." }
Le JWT est valide 60 minutes (valeur par defaut Baserow, configurable cote serveur).
Refresh
POST /api/user/token-refresh/
Content-Type: application/json
{ "token": "eyJ..." (token courant) }
Reponse :
{ "token": "eyJ..." (nouveau token) }
Header d'autorisation
Authorization: JWT eyJ...
Note : le prefixe est JWT, pas Bearer ni Token.
Creer le compte service Baserow
- Ouvrir
http://<baserow-host>/admin/users/ - Cliquer "Add user"
- Remplir :
- Email :
bridge-svc@interne.local(ou equivalent interne) - Password : generer un mot de passe fort (min 16 chars, stocker dans Vault ou secret manager)
- Is active : oui
- Is staff : non (pas besoin d'admin)
- Email :
- Ajouter ce user aux groupes (workspaces) ou il doit lire les tables
- Permission "Member" suffit pour lire views + tables
- Verifier :
curl -X POST http://baserow/api/user/token-auth/ -d '{"username":"bridge-svc@...","password":"..."}'
Variables d'environnement
# Requis pour activer le JWT manager
BASEROW_USER_EMAIL=bridge-svc@interne.local
BASEROW_USER_PASSWORD=generated-strong-password
# Optionnel — refresh le JWT N secondes avant son expiration (defaut 60)
BASEROW_JWT_REFRESH_MARGIN=60
Si ces variables sont absentes, le bridge continue a fonctionner pour les CRUD rows.
Les routes views renvoient 500 BASEROW_USER_AUTH_NOT_CONFIGURED.
Verification que ca marche
Via le health endpoint
curl -s http://localhost:4000/api/health
# { "status": "ok", "service": "bridge", "version": "0.1.0" }
Via la route views
curl -s \
-H "Authorization: Bearer brg_<votre-token>" \
"http://localhost:4000/api/v1/views/table/personne"
# { "data": [...], "total": N }
Avant Patch 031, cette route retournait 401 de Baserow. Apres Patch 031 avec JWT configure, elle retourne les vues de la table.
Verifier les logs au boot
INFO: Baserow user JWT manager enabled (email: bridge-svc@interne.local)
Si vous voyez a la place :
INFO: Baserow user JWT manager disabled — metadata endpoints will return 503 if called
c'est que BASEROW_USER_EMAIL ou BASEROW_USER_PASSWORD est absent.
Architecture interne
getToken() appel ─► BaserowJwtManagerImpl
├─ token cache frais ? → retour immediat
├─ token bientot expire ? → POST /api/user/token-refresh/
│ └─ echec ? → fallback POST /api/user/token-auth/
└─ pas de token ? → POST /api/user/token-auth/
Mutex : si 10 appels simultanes → 1 seul login/refresh, les 9 autres attendent.
BaserowClient.listViewsWithJwt(tableId, jwt) utilise Authorization: JWT <jwt> vers Baserow.
Bonnes pratiques securite
- Le password est remplace par
***dans les logs (voirbaserow-jwt-manager.ts, appelsthis.logger.error) - Le JWT reste en memoire uniquement (pas de Redis, pas de fichier disque)
- Le JWT n'est pas retransmis dans les reponses HTTP du bridge vers les clients
- En cas de rotation du mot de passe Baserow : redemarrer le bridge (re-login au premier appel)
- Stocker BASEROW_USER_PASSWORD dans un secret manager (Vault, Docker secrets, k8s Secret)