[{"data":1,"prerenderedAt":425},["ShallowReactive",2],{"blog-fr-supabase-rls-on-but-table-still-public":3},{"id":4,"title":5,"body":6,"category":387,"cover":388,"coverAlt":388,"description":389,"draft":390,"extension":391,"faq":392,"image":405,"keywords":406,"meta":412,"navigation":413,"ogTitle":414,"path":415,"published":416,"seo":417,"stem":418,"tldr":419,"updated":423,"__hash__":424},"blog_fr\u002Fblog\u002Fsupabase-rls-on-but-table-still-public.md","Supabase Row Level Security est activé. La table reste publique.",{"type":7,"value":8,"toc":376},"minimark",[9,13,21,26,29,32,35,39,42,45,56,77,80,89,93,104,195,201,204,212,216,223,230,233,239,249,253,256,259,298,301,306,310,313,316,327,330,334,363],[10,11,12],"p",{},"Vous avez activé Row Level Security parce que quelque chose vous l'a dit :\nl'advisor dans Supabase, une checklist, le résultat d'un scan, quelqu'un sur un\nDiscord. Le bouton est vert dans votre tableau de bord. Et on vous dit que votre\ntable reste lisible par des inconnus.",[10,14,15,16,20],{},"Voici la partie que guide après guide raconte de travers : ",[17,18,19],"strong",{},"le bouton ne\nprotège rien."," Il décide que vos règles seront consultées. Les règles sont\nautre chose, c'est à vous de les écrire, et la règle la plus rapide à écrire,\ncelle qui remet une app cassée en marche, laisse entrer tout le monde.",[22,23,25],"h2",{"id":24},"row-level-security-est-activé-dans-supabase-comment-la-table-reste-t-elle-publique","Row Level Security est activé dans Supabase. Comment la table reste-t-elle publique ?",[10,27,28],{},"Parce que l'activer et décider qui entre sont deux étapes différentes, et seule\nla première est un bouton.",[10,30,31],{},"Voyez le bouton comme quelqu'un que vous placez à la porte. L'actionner ne\ndécide pas qui passe. Il décide que quelqu'un vérifie désormais une liste. Vos\npolitiques sont cette liste. Une liste vide refuse tout le monde ; une liste qui\ndit « tout le monde » ne refuse personne. Les deux sont Row Level Security\nactivé, et votre tableau de bord affiche le même vert dans les deux cas.",[10,33,34],{},"C'est pourquoi le réglage à lui seul répond à très peu de choses, et pourquoi\nnotre scanner ne demande jamais à Supabase s'il est activé. Il interroge la\ntable. Il envoie la requête qu'enverrait un inconnu, avec la clé publique\nembarquée dans votre app, et regarde si une réponse revient. Il demande un\ndécompte plutôt que les lignes, donc il apprend que la porte s'est ouverte sans\nlire ce qu'il y a derrière.",[22,36,38],{"id":37},"la-politique-qui-a-réparé-votre-app-est-probablement-le-problème","La politique qui a réparé votre app est probablement le problème",[10,40,41],{},"Au moment où vous activez Row Level Security, votre app cesse d'afficher des\ndonnées, et ce que vous avez fait ensuite pour la faire remarcher est justement\nce qui mérite un regard.",[10,43,44],{},"Cette séquence est tout à fait normale, et c'est là que ça dérape. Avec le\nréglage activé et aucune politique écrite, Postgres, le moteur de base de données\nsur lequel tourne Supabase, refuse toutes les requêtes par défaut : vos listes\nreviennent vides et vos écrans restent blancs.\nIl faut bien mettre quelque chose sur la liste. Si vous avez demandé à Cursor ou\nà Lovable de réparer ça, ou collé le premier extrait qui faisait disparaître\nl'erreur, ce que vous avez maintenant ressemble sans doute à ceci :",[46,47,52],"pre",{"className":48,"code":50,"language":51},[49],"language-text","CREATE POLICY \"Enable read access for all users\"\n  ON public.profiles\n  FOR SELECT\n  USING (true);\n","text",[53,54,50],"code",{"__ignoreMap":55},"",[10,57,58,61,62,65,66,69,70,73,74,76],{},[53,59,60],{},"USING (true)"," est la condition qu'une ligne doit remplir avant que la base de\ndonnées ne la livre. Toutes les lignes remplissent ",[53,63,64],{},"true",". Il y a là un second\ndétail facile à dépasser : sans clause ",[53,67,68],{},"TO",", une politique s'applique à\n",[53,71,72],{},"public",", et ",[53,75,72],{}," couvre aussi bien les visiteurs connectés que de parfaits\ninconnus.",[10,78,79],{},"L'app remarche donc, rien n'affiche d'erreur, et la table est exactement aussi\nlisible qu'avant que vous ne commenciez.",[10,81,82,83,88],{},"Cela répare la lecture, et seulement la lecture. Si votre app enregistre aussi\ndans cette table, la chose suivante que vous rencontrez est\n",[84,85,87],"a",{"href":86},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","new row violates row-level security policy",", soit le même réglage qui\nrefuse une écriture, et aucune policy de lecture ne la fera disparaître.",[22,90,92],{"id":91},"les-quatre-états-possibles-dune-table","Les quatre états possibles d'une table",[10,94,95,96,99,100,103],{},"Deux sont sûrs et deux ne le sont pas, et le bouton ne vous dit pas lesquels.\n« Clé publiable » ci-dessous désigne celle qui a sa place dans votre application :\n",[53,97,98],{},"sb_publishable_…"," dans les projets Supabase récents, ",[53,101,102],{},"anon"," dans les anciens.",[105,106,107,126],"table",{},[108,109,110],"thead",{},[111,112,113,117,120,123],"tr",{},[114,115,116],"th",{},"Row Level Security",[114,118,119],{},"La politique",[114,121,122],{},"Votre app",[114,124,125],{},"Un inconnu avec votre clé publiable Supabase",[127,128,129,148,165,179],"tbody",{},[111,130,131,135,138,141],{},[132,133,134],"td",{},"Désactivé",[132,136,137],{},"sans objet, aucune consultée",[132,139,140],{},"Marche",[132,142,143],{},[144,145,147],"key-verdict",{"type":146},"danger","Lit toutes les lignes",[111,149,150,153,156,159],{},[132,151,152],{},"Activé",[132,154,155],{},"aucune écrite",[132,157,158],{},"Cassée",[132,160,161],{},[144,162,164],{"type":163},"safe","Ne lit rien",[111,166,167,169,173,175],{},[132,168,152],{},[132,170,171],{},[53,172,60],{},[132,174,140],{},[132,176,177],{},[144,178,147],{"type":146},[111,180,181,183,188,190],{},[132,182,152],{},[132,184,185],{},[53,186,187],{},"USING (auth.uid() = user_id)",[132,189,140],{},[132,191,192],{},[144,193,194],{"type":163},"Ne lit que les siennes",[196,197],"diagram",{"alt":198,"caption":199,"src":200},"Quatre tables côte à côte. Sur la première le bouton est éteint et les six lignes sont lisibles. Sur la deuxième le bouton est allumé, la case de politique est vide et aucune ligne n'est lisible. Sur la troisième le bouton est allumé avec une politique qui dit true, et les six lignes redeviennent lisibles. Sur la quatrième le bouton est allumé avec une politique qui compare le propriétaire de la ligne, et seules deux lignes sont lisibles.","La marque sous chaque colonne ne suit pas le bouton au-dessus. Deux d'entre elles sont allumées et l'une des deux livre tout.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Frls-four-states-1600x760.png",[10,202,203],{},"Les deux colonnes du milieu sont la paire qui piège les gens. Même réglage, même\npastille verte, résultats opposés, et la différence tient à un mot dans une\nrègle que presque personne n'ouvre.",[10,205,206,207,211],{},"Si vous préférez ne pas lire chaque politique vous-même, notre scan gratuit pose\nà votre base de données en ligne la même question qu'un inconnu et vous dit\nquelles tables ont répondu. Il prend une vingtaine de secondes et ne demande\naucun compte : ",[84,208,210],{"href":209},"\u002F#scan","scanner votre app",".",[22,213,215],{"id":214},"authenticated-ne-veut-pas-dire-à-vous","« Authenticated » ne veut pas dire « à vous »",[10,217,218,219,222],{},"Une politique qui autorise ",[53,220,221],{},"authenticated"," autorise toute personne ayant un\ncompte, ce qui, si votre app a un formulaire d'inscription ouvert, revient à\ntoute personne prête à le remplir.",[10,224,225,226,229],{},"C'est la version plus subtile de la même erreur, et elle survit à beaucoup de\nrelectures parce qu'elle a l'air soigneuse. ",[53,227,228],{},"TO authenticated USING (true)"," se\nlit comme une restriction, et c'en est une : elle exclut ceux qui ne se sont\njamais inscrits. Ce qu'elle ne fait pas, c'est empêcher un de vos clients de\nlire les lignes d'un autre client, ce qui est en général ce que vous entendiez\npar « privé ».",[10,231,232],{},"La règle qui fait cela nomme le propriétaire de la ligne :",[46,234,237],{"className":235,"code":236,"language":51},[49],"CREATE POLICY \"Users read their own rows\"\n  ON public.orders\n  FOR SELECT\n  TO authenticated\n  USING (auth.uid() = user_id);\n",[53,238,236],{"__ignoreMap":55},[10,240,241,244,245,248],{},[53,242,243],{},"auth.uid()"," est celui qui demande. ",[53,246,247],{},"user_id"," est la colonne de la ligne qui dit\nà qui elle appartient. La ligne revient quand les deux correspondent, et reste\noù elle est quand ce n'est pas le cas.",[22,250,252],{"id":251},"comment-vérifier-vos-propres-tables-en-deux-minutes","Comment vérifier vos propres tables en deux minutes",[10,254,255],{},"Ouvrez Supabase, allez dans Authentication → Policies, et lisez l'expression à\nl'intérieur de chaque politique plutôt que la pastille à côté de chaque table.",[10,257,258],{},"Trois choses à repérer :",[260,261,262,271,279],"ul",{},[263,264,265,270],"li",{},[17,266,267,268,211],{},"Une politique dont la condition est ",[53,269,64],{}," Décidez, table par table, si\nvous seriez à l'aise avec ces données sur une page ouverte. Pour une liste\nd'articles publiés, oui. Pour tout ce qui contient une personne, non.",[263,272,273,278],{},[17,274,275,276,211],{},"Une politique sans clause ",[53,277,68],{}," Elle s'applique à tout le monde, connecté\nou non, même quand le reste de la règle paraît très précis.",[263,280,281,284,285,288,289,292,293,297],{},[17,282,283],{},"Une table avec le réglage activé, aucune politique, et une app qui marche\nquand même."," Cette combinaison signifie qu'autre chose atteint vos données,\net l'explication habituelle est une clé secrète (",[53,286,287],{},"sb_secret_…",", ou\n",[53,290,291],{},"service_role"," sur un ancien projet), qui ignore toutes les politiques que\nvous avez écrites.\n",[84,294,296],{"href":295},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Quelles clés d'API sont sûres dans votre frontend","\nexplique comment la distinguer de la clé sûre.",[10,299,300],{},"L'autre vérification vers laquelle on se tourne est d'ouvrir l'app dans une\nfenêtre privée sans se connecter. Elle vaut le coup, mais sachez ce qu'elle\nprouve. Votre app décide de ce qu'elle affiche. Votre base de données décide de\nce qu'elle livre. Ce sont deux décisions différentes, et un inconnu qui saute\nvos écrans obtient la seconde.",[196,302],{"alt":303,"caption":304,"src":305},"Deux chemins vers les mêmes lignes. En passant par les écrans de l'app, deux lignes sur six reviennent. En allant directement à l'adresse de la base de données, les six reviennent.","Les écrans de votre app ne sont pas la clôture. La même table peut montrer deux lignes à travers votre app et livrer les six à une requête qui ne l'a jamais ouverte.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fapp-view-vs-database-1600x620.png",[22,307,309],{"id":308},"à-quoi-cela-ressemble-quand-cela-vous-arrive","À quoi cela ressemble quand cela vous arrive",[10,311,312],{},"À rien. C'est la forme de ce problème, et c'est pour cela qu'il reste en place\ndes mois.",[10,314,315],{},"Aucune erreur n'apparaît dans votre builder. Rien ne ralentit, aucun écran ne\ncasse, aucun e-mail n'arrive. Votre app se comporte exactement comme le jour du\nlancement, parce que de son côté rien n'a changé : elle avait toujours le droit\nde lire ces lignes. Ce qui a changé, c'est que tout le monde y a droit aussi,\navec la clé embarquée dans le code que votre site envoie à chaque visiteur.",[10,317,318,319,322,323,326],{},"Quand cela remonte, cela remonte de biais. Une cliente demande comment quelqu'un\na su une chose que seule votre app savait. Une liste d'adresses que vous n'avez\njamais publiée réapparaît quelque part. Et si la règle généreuse couvre aussi\nl'écriture, ",[53,320,321],{},"FOR ALL"," au lieu de ",[53,324,325],{},"FOR SELECT",", alors n'importe qui peut aussi\nmodifier et supprimer des lignes : c'est la version que les gens découvrent sous\nla forme d'une table soudainement vide.",[10,328,329],{},"Les règles glissent aussi. Une migration, un changement de schéma, une autre\nréparation nocturne qui avait besoin que les données se chargent : chacune peut\ndesserrer une politique sans le dire. C'est pourquoi cela mérite un second\nregard plus tard, et pas seulement un regard maintenant. Surveiller cela fait\npartie de ce que fait Reeve Care, même si un rappel dans votre agenda remplit la\nmême fonction.",[22,331,333],{"id":332},"que-faire-cette-semaine","Que faire cette semaine",[335,336,337],"key-takeaways",{},[260,338,339,342,345,354,360],{},[263,340,341],{},"Ouvrez Authentication → Policies dans Supabase et lisez la condition de chaque politique, table par table. La pastille sur la table n'est pas la réponse.",[263,343,344],{},"Pour chaque table contenant des personnes, utilisateurs, profils, commandes, messages, vérifiez que la règle nomme le propriétaire de la ligne au lieu d'autoriser tout le monde.",[263,346,347,348,350,351,353],{},"Remplacez tout ",[53,349,60],{}," sur ces tables par une règle qui compare ",[53,352,243],{}," à la colonne du propriétaire, puis vérifiez que votre app charge encore.",[263,355,356,357,359],{},"Ajoutez la clause ",[53,358,68],{}," que vous aviez en tête. Une politique sans elle s'applique aux inconnus comme aux visiteurs connectés.",[263,361,362],{},"Si une table a le réglage activé, aucune politique, et que votre app affiche quand même ses données, trouvez ce qui le contourne avant de toucher à autre chose.",[10,364,365,366,370,371,375],{},"Commencez par la table qui vous gênerait le plus si elle était une page\nouverte, et réglez celle-là aujourd'hui. La\n",[84,367,369],{"href":368},"\u002Fchecklist","checklist sécurité en 10 minutes"," couvre ce point avec le reste de\nce qui mérite un contrôle sur une app fraîchement lancée, et le\n",[84,372,374],{"href":373},"\u002Fis-your-supabase-app-safe","guide de sécurité Supabase"," passe en revue ce qui\nreste couramment ouvert.",{"title":55,"searchDepth":377,"depth":377,"links":378},3,[379,381,382,383,384,385,386],{"id":24,"depth":380,"text":25},2,{"id":37,"depth":380,"text":38},{"id":91,"depth":380,"text":92},{"id":214,"depth":380,"text":215},{"id":251,"depth":380,"text":252},{"id":308,"depth":380,"text":309},{"id":332,"depth":380,"text":333},"Bases de la sécurité",null,"Activer Supabase Row Level Security ne protège pas une table. Ce sont vos politiques, et celle qui a réparé votre app laisse peut-être entrer tout le monde.",false,"md",[393,396,399,402],{"q":394,"a":395},"J'ai activé Row Level Security et mon app n'affiche plus de données. Ai-je cassé quelque chose ?","Non, c'est le réglage qui fait son travail. Avec Row Level Security activé et aucune politique écrite, Postgres, le moteur de base de données sous Supabase, refuse toutes les requêtes par défaut, y compris celles de votre propre app. La solution est d'ajouter une politique décrivant qui doit voir quelles lignes. L'erreur à éviter est d'en ajouter une qui autorise tout le monde, parce que c'est la version qui fait remarcher l'app et laisse la table ouverte.",{"q":397,"a":398},"USING (true) est-il parfois la bonne politique ?","Oui, pour des données réellement publiques. Une table d'articles publiés, un catalogue produits, une liste de lieux sur une carte : elles sont faites pour être lues par tout le monde, et une politique qui l'autorise est correcte. Elle cesse de l'être dès que la table contient des personnes. Demandez-vous si vous seriez à l'aise en publiant le contenu de cette table sur une page ouverte, et laissez la réponse décider de la politique.",{"q":400,"a":401},"Row Level Security me protège-t-il si ma clé secrète a fuité ?","Non. Une clé secrète Supabase (sb_secret_ dans les projets récents, service_role dans les anciens) contourne entièrement Row Level Security, c'est sa raison d'être. Toutes les politiques que vous avez écrites sont ignorées, sur toutes les tables. Si cette clé est dans votre frontend, vos politiques ne font rien pour vous, et la faire tourner est le premier chantier, avant tout travail sur les règles.",{"q":403,"a":404},"Ai-je besoin de Row Level Security si mon app a déjà un écran de connexion ?","Oui. Votre écran de connexion contrôle votre app, et votre app n'est pas le seul chemin vers votre base de données. Supabase donne à chaque projet une adresse web qui répond directement aux requêtes, et la clé pour lui parler se trouve dans le code que votre app envoie à chaque visiteur. Les politiques sont la partie qui s'applique quelle que soit la porte empruntée.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",[407,408,409,410,411],"supabase rls","row level security politique","table supabase publique","rls ne fonctionne pas","sécurité supabase",{},true,"Supabase RLS est activé. Votre table est toujours publique.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","2026-08-10",{"title":5,"description":389},"blog\u002Fsupabase-rls-on-but-table-still-public",[420,421,422],"Dans Supabase, l'interrupteur et les règles sont deux choses distinctes. Activé sans règle, personne ne passe ; activé avec la mauvaise règle, tout le monde passe.","La règle qui remet une app cassée en marche est en général celle qui autorise n'importe quelle requête, de n'importe qui.","Lisez la politique, pas le bouton. Un seul mot décide si un inconnu peut lire votre table.","2026-08-12","te9WRtHOEIZmPThY1JqynJ1CbsFoJDS2W_5-qKF_Es0",1787826048205]