Règles de Sécurité PocketBase : Protéger vos données comme un pro – 2026
Dans le monde des startups et des PME, la sécurité des données n'est pas un luxe, c'est une nécessité. Imaginez : vous lancez une app pour gérer vos clients, et sans protections adaptées, n'importe qui pourrait lire ou modifier des informations sensibles. PocketBase, ce backend open-source tout-en-un, intègre un système de règles d'accès et de filtres qui permet de verrouiller cela sans écrire une ligne de code supplémentaire.
Ces règles définissent qui peut faire quoi sur vos collections de données – lister, voir, créer, mettre à jour ou supprimer des enregistrements. Elles agissent comme des gardiens intelligents : elles filtrent les accès et les résultats en temps réel, en s'appuyant sur le contexte de la requête, les champs de la collection et même des calculs géographiques. Pour un public débutant comme vous, entrepreneurs ou développeurs juniors en startup, c'est l'outil parfait pour sécuriser votre projet sans complexité excessive.
Dans cet article, on va décortiquer tout ça pas à pas. On commence par la syntaxe de base, on passe aux règles par action, on explore les opérateurs avancés, on voit comment intégrer les filtres dans les requêtes, et on termine par des exemples concrets applicables à votre business. À la fin, vous saurez configurer des protections granulaires pour que seules les bonnes personnes voient ou touchent les bonnes données. Allons-y.
1. Syntaxe des règles : Les bases pour bien démarrer
Les règles d'API dans PocketBase sont des expressions simples, écrites en texte brut, qui se configurent directement dans l'interface admin de l'outil. Chaque collection (équivalent à une table dans une base de données) dispose de cinq règles principales : listRule, viewRule, createRule, updateRule et deleteRule. Pour les collections d'authentification (comme les utilisateurs), il y a en plus manageRule, qui permet à un utilisateur de gérer un autre compte.
Chaque règle peut prendre trois états :
- "locked" (par défaut, équivalent à
null) : Seuls les superutilisateurs (admins suprêmes) peuvent effectuer l'action. - Chaîne vide (
"") : Tout le monde peut le faire, y compris les invités non authentifiés. - Une expression non vide : Seuls les utilisateurs qui satisfont l'expression peuvent passer.
Ces règles ne se contentent pas de bloquer ; elles filtrent aussi les données retournées. Par exemple, si une règle de liste n'est pas satisfaite pour certains enregistrements, l'API renvoie une liste vide au lieu d'une erreur. C'est doux pour l'utilisateur final, mais ferme sur la sécurité.
La syntaxe suit un format basique : opérande opérateur opérande. Les opérandes peuvent être des champs de la collection (comme status ou email), des chaînes de caractères (entre guillemets simples ou doubles), des nombres, null, true ou false. Les opérateurs relient tout ça – on en parle plus loin.
Mais le vrai pouvoir vient des variables spéciales. Il y en a trois catégories principales :
Les champs de la collection
Ce sont les données de vos enregistrements. Vous pouvez les utiliser directement, y compris pour les relations imbriquées. Exemple : si vous avez un champ relationnel someRelField lié à une autre collection avec un champ status, vous écrivez someRelField.status != "pending". Ça vérifie que le statut lié n'est pas en attente.
@request.* : Le contexte de la requête
C'est là que ça devient concret pour votre app. Ces variables capturent ce qui arrive dans la requête HTTP :
@request.context: Le type de contexte, comme"default","oauth2","otp"(pour code à usage unique),"password","realtime"ou"protectedFile". Utile pour bloquer certaines actions en mode OAuth, par exemple :@request.context != "oauth2".@request.method: La méthode HTTP, comme"GET"ou"POST". Exemple :@request.method = "GET"pour limiter les vues aux lectures.@request.headers.*: Les en-têtes de la requête, normalisés en minuscules et avec les tirets remplacés par des underscores. Par exemple, pour vérifier un token custom :@request.headers.x_token = "test".@request.query.*: Les paramètres d'URL. Si quelqu'un appelle/api/collections/posts?author=123, vous testez@request.query.author = "123".@request.auth.*: L'utilisateur authentifié. Le plus courant :@request.auth.id != ""pour s'assurer que l'utilisateur est connecté. Vous accédez aussi à ses champs, comme@request.auth.emailsi votre collection users a ce champ.@request.body.*: Les données soumises dans le corps de la requête. Exemple :@request.body.title != ""pour forcer un titre lors de la création.
Notez une limite : les fichiers uploadés ne font pas partie de @request.body pour l'instant ; ils sont évalués séparément.
@collection.* : Accès à d'autres collections
Sans relation directe, vous pouvez croiser des données d'autres collections. Syntaxe : @collection.nomCollection.champ ?= votreChamp. Le ?= signifie "au moins un enregistrement correspond". Exemple : @collection.news.categoryId ?= categoryId && @collection.news.author ?= @request.auth.id. Ça vérifie que l'utilisateur est l'auteur d'au moins une news dans cette catégorie.
Pour des jointures complexes sur la même collection, utilisez des alias : @collection.courseRegistrations:auth.user ?= @request.auth.id. Ici, :auth est l'alias pour une seconde instance de la collection.
Ces variables rendent les règles dynamiques et adaptées à des scénarios réels, comme limiter l'accès à un employé qui ne voit que ses propres leads dans une startup de vente.
Pour les débutants, commencez par l'interface admin de PocketBase : elle propose un autocomplétion pour ces syntaxes, ce qui évite les erreurs. Testez toujours en mode dev avant de déployer.
2. Règles par action : Qui peut faire quoi ?
PocketBase applique les règles en fonction de l'action demandée. Ça permet une granularité fine : un utilisateur peut lister des données sans pouvoir les modifier. Voyons chaque type.
listRule : Pour les listes de données
Cette règle contrôle qui peut appeler GET /api/collections/nomCollection et filtre les résultats. Si l'utilisateur ne satisfait pas la règle, il reçoit un tableau vide (code 200), pas d'erreur – pratique pour les apps mobiles qui ne crashent pas.
Exemple basique : Permettre aux utilisateurs connectés de voir seulement les posts actifs ou en attente : @request.auth.id != "" && (status = "active" || status = "pending"). Pour une PME gérant un blog, ça cache les brouillons aux visiteurs anonymes.
Autre cas : Tout le monde voit les produits, mais seulement ceux dont le titre commence par "Promo" : title ~ "Promo%". Le ~ est un opérateur "contient" qu'on détaille après.
viewRule : Pour la consultation d'un enregistrement unique
Pour GET /api/collections/nomCollection/id. Si la règle échoue, c'est un 404 (non trouvé), ce qui masque l'existence de l'enregistrement.
Exemple : Seulement les utilisateurs connectés : @request.auth.id != "". Pour une startup de freelances, ajoutez une vérification propriétaire : @request.auth.id = owner_id, où owner_id est un champ relationnel vers la collection users.
Ou pour un accès restreint : @request.auth.id != "" && allowed_users.id ?= @request.auth.id, si allowed_users est une relation multiple listant les autorisés.
createRule : Pour la création
Contrôle POST /api/collections/nomCollection. Si échec, 400 (mauvaise requête).
Exemple : Création ouverte à tous, mais avec un titre obligatoire : @request.body.title != "". Pour sécuriser, ajoutez l'auth : @request.auth.id != "" && @request.body.title != "". Dans une app de tâches pour PME, forcez un assigné : @request.body.assigned_to != null.
updateRule : Pour les modifications
Pour PATCH /api/collections/nomCollection/id. Échec = 404.
Exemple : Seul le propriétaire ou un admin modifie : @request.auth.id = owner_id || @request.auth.role = "admin". Ici, role est un champ dans la collection users. Idéal pour que les employés d'une startup ne touchent pas les leads des collègues.
deleteRule : Pour les suppressions
Pour DELETE /api/collections/nomCollection/id. Échec = 404.
Exemple strict : @request.auth.id = owner_id. Pas d'admin ici, pour éviter les suppressions accidentelles dans une petite équipe.
Pour les collections auth (comme _users), manageRule est spécial : elle permet de gérer un autre utilisateur. Exemple : @request.auth.admin = true, pour que seuls les admins changent les mots de passe.
Les superutilisateurs ignorent toutes ces règles – c'est normal, ils sont vos admins internes. Dans une startup, limitez-les à 1-2 personnes.
Ces règles s'évaluent à chaque requête, en tenant compte de l'état actuel de l'enregistrement. Utilisez des parenthèses pour grouper : (A && B) || C.
3. Opérateurs avancés : Rendez vos règles puissantes
Les opérateurs sont le cœur des expressions. Sans eux, vos règles seraient trop rigides. PocketBase en propose pour les comparaisons basiques, les chaînes, les nombres, les dates, la logique, et même la géo.
Opérateurs de base
=et!=: Égalité et inégalité. Pour tout type.>,>=,<,<=: Comparaisons numériques ou dates.
Exemple : price >= 100 pour filtrer les produits chers.
Pour les chaînes et recherches
~: Contient (like, avec % automatique si pas spécifié). Exemple :title ~ "test"trouve "My test post".!~: Ne contient pas.
Pour les relations multiples (comme une liste de tags), utilisez les versions "any" :
?=: Au moins un égal (pour relations ou arrays).?!=,?>, etc.
Exemple : @collection.comments.author ?= @request.auth.id – l'utilisateur a au moins un commentaire sur cet article.
Logique et grouping
&&(ET),||(OU),( )pour grouper.- Commentaires :
// Ceci est un commentaire.
Exemple complexe : @request.auth.id != "" && (status = "active" || (category = "news" && views > 100)).
Modificateurs spéciaux
Ces petits ajouts transforment les opérateurs :
:isset: Vérifie si un champ est présent dans la requête. Exemple :@request.body.role :isset = false– interdit de soumettre un rôle.:changed: Vérifie si un champ a été soumis ET changé. Exemple :@request.body.role :changed = false– empêche de modifier le rôle existant.:length: Nombre d'éléments dans un array (relation, select, file). Exemple :tags :length <= 5– max 5 tags.:each: Applique à chaque élément. Exemple :tags :each ~ "pb_"– tous les tags doivent commencer par "pb_".:lower: Comparaison insensible à la casse. Exemple :email :lower = "[email protected]".
Note : Ces modificateurs ne gèrent pas encore les nouveaux fichiers uploadés.
Macros pour les dates et heures
Tout en UTC :
@now: Timestamp actuel.@second,@minute,@hour,@weekday(0-6, dimanche=0),@day,@month,@year.@yesterday,@tomorrow.@todayStart/@todayEnd,@monthStart/@monthEnd,@yearStart/@yearEnd.
Exemple : @request.body.eventDate >= @now – événements futurs seulement.
Fonctions géographiques
geoDistance(lonA, latA, lonB, latB) : Distance en km via Haversine. Arguments : nombres ou champs geoPoint.
Exemple : geoDistance(address.lon, address.lat, 23.32, 42.69) < 25 – bureaux à moins de 25 km d'un point.
Pour une startup de livraison, c'est gold : filtrez les commandes locales sans code extra.
Ces opérateurs rendent PocketBase flexible pour des cas PME/startup : validations auto, anti-spam, localisation.
4. Filtres dans les requêtes : Appliquez les règles en action
Les filtres ne sont pas que dans les règles ; vous les utilisez aussi dans les appels API pour raffiner les résultats côté client. Syntaxe identique aux règles, mais passés en paramètre ?filter=.
Exemple : GET /api/collections/posts?filter=(status="active" && author="@request.auth.id"). Ça liste seulement les posts actifs de l'utilisateur connecté.
Les filtres supportent tous les opérateurs et variables @request.*, mais pas @collection.* (pour éviter des boucles coûteuses). Pour les relations, utilisez expand : ?expand=author pour inclure les données liées, puis filtrez dessus.
Dans les règles, les filtres s'appliquent en amont : la listRule filtre d'abord, puis votre filtre client affine. Si la règle renvoie vide, votre filtre n'a rien à traiter.
Pour les PME, c'est pratique : un employé voit tous les clients, mais filtre par ville via l'app. Exemple de requête : ?filter=geoDistance(city.lon, city.lat, @request.query.userLon, @request.query.userLat) < 50.
Gestion des erreurs : Si un filtre est invalide, 400. Paginez avec ?page=1&perPage=20 pour scaler.
Intégrez ça dans votre SDK JS ou Go : pb.collection('posts').getList(1, 20, { filter: 'status="active"' }).
5. Exemples concrets : Appliquez à votre projet
Passons à la pratique. Supposons une startup de gestion de projets avec collections projects (champs : title, status, owner relation vers users, team relation multiple) et users (avec role : "admin", "member").
Exemple 1 : Liste sécurisée pour membres d'équipe
Pour listRule sur projects : @request.auth.id != "" && (@request.auth.id = owner || team.id ?= @request.auth.id) && status != "archived".
Résultat : Un membre voit ses projets perso + ceux de son équipe, sans les archivés. Appel API : vide si non connecté, sinon filtré.
Exemple 2 : Création avec validation
createRule : @request.auth.id != "" && @request.body.title :length >= 3 && @request.body.status :isset = false.
Force un titre d'au moins 3 chars, mais status par défaut (pas soumis). Pour update : @request.body.status :changed = false || @request.auth.role = "admin".
Exemple 3 : Accès géo pour services locaux
Collection services avec geoPoint location. viewRule : @request.auth.id != "" && geoDistance(location.lon, location.lat, @request.query.lat, @request.query.lon) <= 100.
Un client connecté voit un service si <100km. Filtre client : ?filter=category="plombier".
Exemple 4 : Protection anti-changement sensible
Pour users updateRule : @request.auth.id = id || @request.auth.admin = true (où id est l'ID de l'utilisateur édité). Ajoutez @request.body.email :changed = false || @request.auth.admin = true.
Empêche de changer son propre email sans admin.
Exemple 5 : Croisement collections pour audits
listRule sur audits : @request.auth.id != "" && @collection.projects.owner ?= @request.auth.id.
L'utilisateur voit les audits de ses projets, sans relation directe.
Testez en admin UI : Créez une collection test, appliquez, appelez l'API avec Postman. Pour une PME, commencez simple (auth basique), ajoutez geo ou :each au fur et à mesure.
Erreurs courantes : Oublier les guillemets sur chaînes, mal grouper. Utilisez l'autocomplétion.
Conclusion : Sécurisez sans effort
Les règles et filtres de PocketBase offrent une sécurité granulaire qui s'adapte à votre croissance – de la startup solo à la PME avec équipes. Pas de boilerplate code, juste des expressions puissantes pour protéger owner_id, relations et données sensibles. Implémentez-les dès aujourd'hui : votre app sera robuste, scalable, et conforme RGPD sans sueur.
Pour aller plus loin, explorez les hooks JS pour des logs custom. Questions ? Commentez ci-dessous.