Supabase Edge Function with verify_jwt = false: is it open to anyone? Yes, unless the function checks the caller
Short answer: yes. With verify_jwt = false (or --no-verify-jwt), anyone who knows the function URL can call it, and your code is the only check left. That is right for signed webhooks and health checks. For anything that reads or writes user data, check the caller inside the function, then test signed out. To see what your own live site gives away, run a free SniffPup scan (SniffPup is a free passive security scanner for vibe-coded apps). Only check sites you own.
Home › Guides › Edge Function verify_jwt = false · Last updated · By Ember, SniffPup
The fast way: a free SniffPup scan runs 15 checks from the outside: leaked keys in your public JavaScript, exposed endpoints and security headers. No signup. Ember reads the live site only, so she can't see your Edge Function settings. Use the steps below for that.
A 100 means no issues were found in our checks. It is never proof of security.
1. What the setting does
By default Supabase checks for a valid JWT on the Authorization header before your function runs. The function configuration docs show how to turn that off per function, and warn that it "will allow anyone to invoke your Edge Function without a valid JWT":
# supabase/config.toml [functions.stripe-webhook] verify_jwt = false
A common way it ends up on the wrong function: a call fails with a 401 while you build, and the quick fix is to turn the check off. Supabase's Securing Edge Functions page says to leave it on for user-facing functions, because turning it off leaves your own code as the only thing that verifies the caller.
2. Find functions with the check off
Search your repo for both ways to turn it off:
grep -n -B1 "verify_jwt *= *false" supabase/config.toml grep -rn "no-verify-jwt" package.json .github scripts 2>/dev/null
For each hit, write down who is meant to call it. A webhook from Stripe or GitHub, a cron job, or a health check is a fair reason. A function your app's signed-in users call (profile, billing, admin, AI chat) is not.
3. Fix it
User-facing function: turn the check back on and also check the user inside the handler. The platform check proves a valid JWT is present; your app's public key can pass it too (see the API keys docs), so don't treat it as "signed in":
# supabase/config.toml
[functions.profile]
verify_jwt = true
// supabase/functions/profile/index.ts
import { withSupabase } from 'npm:@supabase/server@1'
export default {
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
// ctx.supabase follows the caller's RLS policies
const { data } = await ctx.supabase.from('profiles').select('*')
return Response.json(data)
}),
}Use ctx.supabase, not ctx.supabaseAdmin, unless the work truly has to cross RLS. The admin client bypasses RLS, so a query through it without a filter on the caller's id returns every user's rows.
Webhook: keep verify_jwt = false and verify the provider's signature before doing anything (for Stripe, constructEventAsync with your webhook secret). Cron or service call: keep it off and use auth: 'secret' so only your secret key gets in. Never put that secret key in client code.
4. Test it
Call each function the way a stranger would. A user-facing function should refuse both:
# no credentials at all: expect 401 curl -i -X POST "https://YOUR-PROJECT.supabase.co/functions/v1/profile" # only your public key, signed out: expect 401 from your own check curl -i -X POST "https://YOUR-PROJECT.supabase.co/functions/v1/profile" \ -H "apikey: YOUR_PUBLIC_KEY" -H "Authorization: Bearer YOUR_PUBLIC_KEY"
Then sign in as a second test user and make sure the function only returns that user's data. For a webhook, send a request with a wrong signature and expect a 400. More on keys: Is the Supabase anon key safe?
FAQ
What does verify_jwt = false do on a Supabase Edge Function?
It turns off the platform check that a valid JWT is on the Authorization header before your code runs. Supabase's function configuration docs warn that it allows anyone to invoke the function without a valid JWT. The same happens with the --no-verify-jwt flag.
When is it fine to turn it off?
For callers that can't send a Supabase token: a Stripe or GitHub webhook (verify the provider's signature inside the handler), a cron job or another service (check a secret key inside the handler), or a truly public endpoint like a health check. Supabase's auth docs use exactly these cases.
Is verify_jwt = true enough to make a function signed-in users only?
Not on its own. The platform check proves a valid JWT is present, and requests made with your public key can pass it, so a signed-out visitor using your app's own key may still reach the handler. If the function is for signed-in users, check the user inside it (for example with auth: 'user' in the withSupabase wrapper) and use the RLS-scoped client, not the service role client.
Can a SniffPup scan see my Edge Function settings?
No. SniffPup reads your live site from the outside (leaked keys in your JavaScript, exposed endpoints, headers). It can't read your config.toml or call your functions as a user. Use the steps in this guide for that.
Sources: Supabase Function Configuration, Securing Edge Functions and API keys docs. Checked November 2, 2026.
A score of 100 means no issues were found in our checks. It is not proof that your app is secure.