Does verify_jwt protect my Supabase edge functions?

No, not on its own. The public anon key is a valid JWT, so verify_jwt lets through anyone who copies it from your site. The function itself must check who the user is, and whether they may act on what they asked for.

Why

With verify_jwt on, Supabase rejects requests without a valid token for your project. But your site ships the anon key, and it counts as a valid token. So a function that sends email, charges a card or returns a file can be called by anyone, from anywhere.

The fix is to read the caller's own session inside the function: pass the request's Authorization header to a Supabase client and call auth.getUser(). No user means 401. Then make sure that user owns the record or document they asked about, instead of trusting ids from the request body.

Functions that are meant to be public (a contact form, a webhook) need other protection: a CAPTCHA, a rate limit, or a verified signature from the service calling it.

How to check

  1. For each function in supabase/functions, look for auth.getUser() (or a verified signature for webhooks) before it does anything.
  2. Check that recipients, amounts and record ids come from your database, not from the request body.
  3. Shippable's code scan flags functions with no caller check: npx shippable-dev scan localhost:5173 in your project.
supabase/functions/your-function/index.ts
const supabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_ANON_KEY")!, { global: { headers: { Authorization: req.headers.get("Authorization") ?? "" } } }, ); const { data: { user } } = await supabase.auth.getUser(); if (!user) return new Response("Unauthorized", { status: 401 });

More on this: Endpoints and functions without access checks, from the Vibe-Code Top 10.

Check your app

Your first app is free, and it is read-only. You prove the app is yours with a one-line tag first.

More questions

Updated 2026-10-06.