[{"data":1,"prerenderedAt":200},["ShallowReactive",2],{"blog-blueprints/vue-supabase":3},{"id":4,"title":5,"body":6,"category":180,"date":181,"dateModified":181,"description":182,"draft":183,"extension":184,"faq":185,"featured":183,"headerVariant":186,"image":185,"keywords":185,"meta":187,"navigation":188,"ogDescription":189,"ogTitle":185,"path":190,"readTime":191,"schemaOrg":192,"schemaType":193,"seo":194,"sitemap":195,"stem":196,"tags":197,"twitterCard":198,"__hash__":199},"blog/blog/blueprints/vue-supabase.md","Vue + Supabase Security Blueprint",{"type":7,"value":8,"toc":169},"minimark",[9,20,23,29,34,49,53,62,66,75,84,88,93,96,99,102,105,108,122,157],[10,11,12],"blueprint-summary",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"To secure a Vue + Supabase SPA,"," you need to: (1) enable RLS on all tables since Vue SPAs have no server layer, (2) use Pinia for reactive auth state management, (3) implement vue-router navigation guards for UX (not security), (4) use only the anon key in client code, and (5) test RLS policies thoroughly before launch. This blueprint covers Vue 3 Composition API patterns with Supabase.",[21,22],"blueprint-meta",{},[24,25,26],"tldr",{},[13,27,28],{},"Vue SPAs with Supabase rely entirely on RLS for data security. Key tasks: enable RLS on all tables, use Pinia for reactive auth state, add vue-router navigation guards for UX (not security), and remember that route guards are client-side only-RLS is your actual security layer.",[30,31,33],"h2",{"id":32},"rls-configuration-supabase","RLS Configuration Supabase",[35,36,38],"code-block",{"label":37},"RLS policies for Vue SPA",[39,40,45],"pre",{"className":41,"code":43,"language":44},[42],"language-text","-- Users can only access their own data\nCREATE POLICY \"User data isolation\"\n  ON user_data FOR ALL\n  USING (auth.uid() = user_id);\n\n-- Public read, authenticated write\nCREATE POLICY \"Public posts\"\n  ON posts FOR SELECT\n  USING (true);\n\nCREATE POLICY \"Authenticated create\"\n  ON posts FOR INSERT\n  WITH CHECK (auth.uid() = author_id);\n","text",[46,47,43],"code",{"__ignoreMap":48},"",[30,50,52],{"id":51},"auth-store-with-pinia-vue","Auth Store with Pinia Vue",[35,54,56],{"label":55},"stores/auth.ts",[39,57,60],{"className":58,"code":59,"language":44},[42],"import { defineStore } from 'pinia'\nimport { supabase } from '@/lib/supabase'\n\nexport const useAuthStore = defineStore('auth', {\n  state: () => ({\n    user: null as User | null,\n    loading: true,\n  }),\n\n  actions: {\n    async init() {\n      const { data } = await supabase.auth.getSession()\n      this.user = data.session?.user ?? null\n      this.loading = false\n\n      supabase.auth.onAuthStateChange((_event, session) => {\n        this.user = session?.user ?? null\n      })\n    },\n  },\n})\n",[46,61,59],{"__ignoreMap":48},[30,63,65],{"id":64},"router-guards-vue","Router Guards Vue",[35,67,69],{"label":68},"router/index.ts - UX only, not security",[39,70,73],{"className":71,"code":72,"language":44},[42],"router.beforeEach(async (to, from, next) => {\n  const authStore = useAuthStore()\n\n  // Wait for auth to initialize\n  if (authStore.loading) {\n    await new Promise(resolve => {\n      const unwatch = watch(() => authStore.loading, (loading) => {\n        if (!loading) { unwatch(); resolve(true) }\n      })\n    })\n  }\n\n  if (to.meta.requiresAuth && !authStore.user) {\n    next('/login')\n  } else {\n    next()\n  }\n})\n",[46,74,72],{"__ignoreMap":48},[76,77,78],"warning-box",{},[13,79,80,83],{},[16,81,82],{},"Router guards are UX only."," Any JavaScript can be disabled or bypassed. Your Supabase RLS policies are the only real security layer.",[30,85,87],{"id":86},"security-checklist","Security Checklist",[89,90,92],"h4",{"id":91},"pre-launch-checklist","Pre-Launch Checklist",[13,94,95],{},"RLS enabled on all tables",[13,97,98],{},"RLS policies tested thoroughly",[13,100,101],{},"Auth state managed with Pinia",[13,103,104],{},"Only anon key in client code",[13,106,107],{},"Environment variables configured",[109,110,111,117],"related-articles",{},[112,113],"related-card",{"description":114,"href":115,"title":116},"With server-side rendering","/blog/blueprints/nuxt-supabase","Nuxt + Supabase",[112,118],{"description":119,"href":120,"title":121},"Deep dive","/blog/guides/supabase","Supabase Security Guide",[123,124,125,130,133],"stack-comparison",{},[126,127,129],"h3",{"id":128},"alternative-stacks","Alternative Stacks",[13,131,132],{},"Consider these related blueprints:",[134,135,136,143,150],"ul",{},[137,138,139,142],"li",{},[140,141,116],"a",{"href":115}," - With server-side rendering",[137,144,145,149],{},[140,146,148],{"href":147},"/blog/blueprints/vue-firebase","Vue + Firebase"," - Firebase/Firestore alternative",[137,151,152,156],{},[140,153,155],{"href":154},"/blog/blueprints/react-supabase","React + Supabase"," - React framework alternative",[158,159,162,166],"cta-box",{"href":160,"label":161},"/","Start Free Scan",[30,163,165],{"id":164},"building-with-this-stack","Building with this stack?",[13,167,168],{},"Scan for RLS issues.",{"title":48,"searchDepth":170,"depth":170,"links":171},2,[172,173,174,175,179],{"id":32,"depth":170,"text":33},{"id":51,"depth":170,"text":52},{"id":64,"depth":170,"text":65},{"id":86,"depth":170,"text":87,"children":176},[177],{"id":128,"depth":178,"text":129},3,{"id":164,"depth":170,"text":165},"blueprints","2026-02-13","Security guide for Vue + Supabase stack. Configure RLS, handle authentication with Pinia, protect routes with vue-router guards, and secure your Vue SPA.",false,"md",null,"purple",{},true,"Complete security configuration for Vue apps with Supabase.","/blog/blueprints/vue-supabase","9 min read","[object Object]","Article",{"title":5,"description":182},{"loc":190},"blog/blueprints/vue-supabase",[],"summary_large_image","-W2l7orlCNt0fBKnJeqbqzA4qS6DD-bshcHEz7omJ74",1775843931995]