[{"data":1,"prerenderedAt":200},["ShallowReactive",2],{"blog-blueprints/astro-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/astro-supabase.md","Astro + 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 an Astro + Supabase site,"," you need to: (1) understand your render mode (static vs SSR) since security patterns differ, (2) verify auth server-side using getUser() in SSR pages and API routes, (3) enable RLS on all tables as defense-in-depth, (4) use access tokens from cookies for server-side auth, and (5) use the anon key only (never service_role on client). This blueprint covers Astro's hybrid rendering with Supabase patterns.",[21,22],"blueprint-meta",{},[24,25,26],"tldr",{},[13,27,28],{},"Astro's hybrid rendering means security depends on your output mode. For static pages, rely on RLS. For SSR pages and API routes, verify auth server-side. Use @astrojs/vercel or similar adapters for server functionality and always enable RLS as defense in depth.",[30,31,33],"h2",{"id":32},"supabase-client-configuration-supabase-astro","Supabase Client Configuration Supabase Astro",[35,36,38],"code-block",{"label":37},"src/lib/supabase.ts",[39,40,45],"pre",{"className":41,"code":43,"language":44},[42],"language-text","import { createClient } from '@supabase/supabase-js'\n\n// Client-side (anon key only)\nexport const supabase = createClient(\n  import.meta.env.PUBLIC_SUPABASE_URL,\n  import.meta.env.PUBLIC_SUPABASE_ANON_KEY\n)\n\n// Server-side (for API routes)\nexport function createServerClient(accessToken?: string) {\n  return createClient(\n    import.meta.env.PUBLIC_SUPABASE_URL,\n    import.meta.env.PUBLIC_SUPABASE_ANON_KEY,\n    {\n      global: {\n        headers: accessToken\n          ? { Authorization: `Bearer ${accessToken}` }\n          : {},\n      },\n    }\n  )\n}\n","text",[46,47,43],"code",{"__ignoreMap":48},"",[30,50,52],{"id":51},"protected-ssr-page-astro","Protected SSR Page Astro",[35,54,56],{"label":55},"src/pages/dashboard.astro",[39,57,60],{"className":58,"code":59,"language":44},[42],"---\nexport const prerender = false  // Enable SSR\n\nimport { createServerClient } from '../lib/supabase'\n\nconst accessToken = Astro.cookies.get('sb-access-token')?.value\n\nif (!accessToken) {\n  return Astro.redirect('/login')\n}\n\nconst supabase = createServerClient(accessToken)\nconst { data: { user } } = await supabase.auth.getUser()\n\nif (!user) {\n  return Astro.redirect('/login')\n}\n\nconst { data: posts } = await supabase\n  .from('posts')\n  .select('*')\n  .eq('user_id', user.id)\n---\n\n\u003Chtml>\n  \u003Cbody>\n    \u003Ch1>Dashboard\u003C/h1>\n    {posts?.map(post => \u003Carticle>{post.title}\u003C/article>)}\n  \u003C/body>\n\u003C/html>\n",[46,61,59],{"__ignoreMap":48},[30,63,65],{"id":64},"api-endpoint-astro","API Endpoint Astro",[35,67,69],{"label":68},"src/pages/api/posts.ts",[39,70,73],{"className":71,"code":72,"language":44},[42],"import type { APIRoute } from 'astro'\nimport { createServerClient } from '../../lib/supabase'\n\nexport const POST: APIRoute = async ({ request, cookies }) => {\n  const accessToken = cookies.get('sb-access-token')?.value\n\n  if (!accessToken) {\n    return new Response('Unauthorized', { status: 401 })\n  }\n\n  const supabase = createServerClient(accessToken)\n  const { data: { user } } = await supabase.auth.getUser()\n\n  if (!user) {\n    return new Response('Unauthorized', { status: 401 })\n  }\n\n  const body = await request.json()\n\n  const { data, error } = await supabase.from('posts').insert({\n    title: body.title,\n    user_id: user.id,\n  }).select().single()\n\n  if (error) {\n    return new Response(JSON.stringify({ error: error.message }), { status: 400 })\n  }\n\n  return new Response(JSON.stringify(data), { status: 201 })\n}\n",[46,74,72],{"__ignoreMap":48},[76,77,78],"warning-box",{},[13,79,80,83],{},[16,81,82],{},"Know your render mode."," Static pages (default) have no server-security is 100% RLS. SSR pages and API routes run server-side but still need RLS as defense in depth.",[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],{},"Auth verified in SSR pages",[13,100,101],{},"Auth verified in API routes",[13,103,104],{},"getUser() used for verification",[13,106,107],{},"Output mode understood per page",[109,110,111,117],"related-articles",{},[112,113],"related-card",{"description":114,"href":115,"title":116},"Pure static","/blog/blueprints/jamstack-supabase","Jamstack + 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}," - Pure static approach",[137,144,145,149],{},[140,146,148],{"href":147},"/blog/blueprints/nextjs-supabase-vercel","Next.js + Supabase + Vercel"," - React/Next.js alternative",[137,151,152,156],{},[140,153,155],{"href":154},"/blog/blueprints/sveltekit-supabase","SvelteKit + Supabase"," - Svelte alternative",[158,159,162,166],"cta-box",{"href":160,"label":161},"/","Start Free Scan",[30,163,165],{"id":164},"check-your-astro-supabase-site","Check Your Astro + Supabase Site",[13,167,168],{},"Scan for auth and 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-01-26","Security guide for Astro sites with Supabase. Configure RLS, secure server endpoints, handle hybrid rendering auth, and protect your Astro app with proper security patterns.",false,"md",null,"purple",{},true,"Complete security configuration for Astro with Supabase.","/blog/blueprints/astro-supabase","10 min read","[object Object]","Article",{"title":5,"description":182},{"loc":190},"blog/blueprints/astro-supabase",[],"summary_large_image","9-e1M4grx1iZ1hwJAobtTjCCA6f5WkTyDeZsZQI57H8",1775843932936]