[{"data":1,"prerenderedAt":166},["ShallowReactive",2],{"blog-diagrams/supabase-key-trust-boundary":3},{"id":4,"title":5,"body":6,"category":140,"date":141,"dateModified":141,"description":142,"draft":143,"extension":144,"faq":145,"featured":143,"headerVariant":150,"image":151,"keywords":152,"meta":153,"navigation":154,"ogDescription":155,"ogTitle":151,"path":156,"readTime":157,"schemaOrg":158,"schemaType":159,"seo":160,"sitemap":161,"stem":162,"tags":163,"twitterCard":164,"__hash__":165},"blog/blog/diagrams/supabase-key-trust-boundary.md","Supabase Keys and the Trust Boundary (Diagram)",{"type":7,"value":8,"toc":133},"minimark",[9,13,16,22,27,30,33,36,39,58,62,65,68,102,121],[10,11,12],"p",{},"Both of your Supabase keys reach the same database. Only one of them gets checked on the way in.",[10,14,15],{},"That single sentence is behind a large share of the exposed-database incidents we see in scans of AI-built apps. The publishable key is meant to sit in your frontend where anyone can read it. The secret key is not, and it ignores every policy you have written.",[17,18],"diagram",{"alt":19,"caption":20,"src":21},"The publishable key travels from the browser through a Row Level Security check before reaching the database, while the secret key travels from your server directly to the database with no check","Both keys reach the same database. Only one is checked.","supabase-key-trust-boundary",[23,24,26],"h2",{"id":25},"reading-the-diagram","Reading the diagram",[10,28,29],{},"The red zone at the top is your browser. Treat everything in it as public, because it is: anyone can open devtools, read your JavaScript bundle, and copy whatever is in it. Putting the publishable key there is fine and expected.",[10,31,32],{},"The amber diamond is Row Level Security. It's the only thing standing between a public key and your data. Every request carrying the publishable key gets filtered through your policies, and the reader gets back only the rows those policies allow.",[10,34,35],{},"The green zone is your server: an API route, an Edge Function, anything the browser can't read. The secret key belongs here and nowhere else.",[10,37,38],{},"Now follow the red arrow. The secret key doesn't touch the diamond. It goes straight to the database and reads every row in every table. That's the entire point of the key, and it's why the arrow is drawn the way it is.",[40,41,42],"warning-box",{},[10,43,44,48,49,53,54,57],{},[45,46,47],"strong",{},"The failure mode is a one-character mistake."," Prefixing the secret key with ",[50,51,52],"code",{},"NEXT_PUBLIC_"," or ",[50,55,56],{},"VITE_"," moves it out of the green box and into the red one. The app keeps working, so nothing tells you anything is wrong. Meanwhile the key that skips every check is now in a file anyone can download.",[23,59,61],{"id":60},"why-rls-being-off-changes-the-picture","Why RLS being off changes the picture",[10,63,64],{},"If Row Level Security isn't enabled on a table, the amber diamond isn't there for that table. The publishable key path becomes the secret key path: straight through, every row.",[10,66,67],{},"This is worth sitting with, because it means \"we only ship the publishable key\" is not by itself a safe position. It's safe only in combination with RLS actually being on, for every table, with policies that say what you think they say.",[69,70,71,78,84],"faq-section",{},[72,73,75],"faq-item",{"question":74},"Is it safe to put the Supabase publishable key in my frontend?",[10,76,77],{},"Yes, that is what it is for. It identifies your project, and what it can actually read is decided by your Row Level Security policies. The catch is that this is only true if RLS is turned on. With RLS off, the publishable key reads everything, which is the single most common way vibe-coded Supabase apps leak data.",[72,79,81],{"question":80},"What happens if my secret key ends up in the browser?",[10,82,83],{},"Anyone who opens your JavaScript bundle can read every row of every table, write to them, and delete them. The secret key skips Row Level Security entirely, so no policy you write will stop it. Rotate it immediately.",[72,85,87],{"question":86},"How do I tell which key I have?",[10,88,89,90,93,94,97,98,101],{},"The new keys are readable at a glance: ",[50,91,92],{},"sb_publishable_"," is the public one, ",[50,95,96],{},"sb_secret_"," is the private one. The older keys were both JWTs starting ",[50,99,100],{},"eyJhbGci"," and looked identical, which is exactly why people shipped the wrong one.",[103,104,105,111,116],"related-articles",{},[106,107],"related-card",{"description":108,"href":109,"title":110},"Migrating to sb_publishable_ and sb_secret_, and checking whether yours is in your frontend","/blog/how-to/supabase-new-api-keys","Supabase Is Retiring service_role Keys",[106,112],{"description":113,"href":114,"title":115},"Turning on the check that the diagram's amber diamond represents","/blog/how-to/setup-supabase-rls","How to Set Up Supabase RLS",[106,117],{"description":118,"href":119,"title":120},"What to do when the secret key has already leaked","/blog/how-to/fix-supabase-api-key-exposure","How to Fix Supabase API Key Exposure",[122,123,126,130],"cta-box",{"href":124,"label":125},"/","Start Free Scan",[23,127,129],{"id":128},"not-sure-which-key-your-app-is-shipping","Not sure which key your app is shipping?",[10,131,132],{},"A scan reads your deployed bundle and tells you what's in it.",{"title":134,"searchDepth":135,"depth":135,"links":136},"",2,[137,138,139],{"id":25,"depth":135,"text":26},{"id":60,"depth":135,"text":61},{"id":128,"depth":135,"text":129},"diagrams","2026-07-31","A diagram of what your publishable key and secret key can each reach in Supabase, and why only one of them gets checked by Row Level Security.",false,"md",[146,147,148],{"question":74,"answer":77},{"question":80,"answer":83},{"question":86,"answer":149},"The new keys are readable at a glance: sb_publishable_ is the public one, sb_secret_ is the private one. The older keys were both JWTs starting eyJhbGci and looked identical, which is exactly why people shipped the wrong one.","blue",null,"supabase trust boundary, supabase publishable key, supabase secret key, row level security diagram, sb_secret vs sb_publishable",{},true,"Both Supabase keys reach the same database. Only one of them is checked.","/blog/diagrams/supabase-key-trust-boundary","3 min read","[object Object]","Article",{"title":5,"description":142},{"loc":156},"blog/diagrams/supabase-key-trust-boundary",[],"summary_large_image","3zmzbKUVhtWH7M7naCmRl0USj0UeaS87LyxZWRFoP8I",1785543175821]