Supabase Edge Function returns 401 (verify_jwt)

An Edge Function returns 401 before your code runs? JWT verification is on, and the Authorization header is missing or is not a user JWT.

Reviewed October 16, 2026

What it means in plain English

A 401 from an Edge Function is either the platform's JWT check or your own code. Supabase's status-code page says 401 means JWT verification is enabled and the request had an invalid or missing JWT.

When verify_jwt is on, that check runs before your function. The default is on. If it fails, your code never runs. The body is then one of the platform messages, including Missing authorization header or Invalid Token or Protected Header formatting. A message you wrote yourself means your function did run and returned 401 on purpose.

Likely causes

  • A webhook (Stripe, GitHub, a database webhook) called the function with no Supabase Authorization header. Those senders do not have a user JWT.
  • The project uses the new sb_publishable / sb_secret keys. Supabase says the legacy JWT check only understands the old JWT-based keys, so it rejects the new ones. See Invalid JWT after switching to sb_publishable or sb_secret keys.
  • The browser called the function with fetch and did not send Authorization. supabase.functions.invoke adds that header. A hand-written fetch does not.
  • The function code itself returns status 401. The troubleshooting guide says to search the function for 401.

How to fix it, step by step

  1. Read the response body. Missing authorization header or Invalid Token or Protected Header formatting is the platform check. A sentence you wrote is your code. Supabase's 401 guide also has a SQL query against function_edge_logs that labels the cause your_code_returned_401, incompatible_keys, invalid_key, or missing_auth_header.
  2. If your code returned 401, search the function for status: 401 and fix that branch. A third-party API can also be the source if you forward its status.
  3. For a function that only your signed-in app calls, leave verify_jwt on. Call it with supabase.functions.invoke, or send Authorization: Bearer with a user JWT. Supabase says the client libraries add the header.
  4. For a webhook or any caller that cannot send a user JWT, turn the platform check off for that function only, then verify the caller inside the function (Stripe's signature, for example). Supabase's function config uses:
[functions.stripe-webhook]
verify_jwt = false

Replace stripe-webhook with the function name. Redeploy after you change it.

  1. You can also turn the check off without editing that file. In the Functions dashboard, open the function's detail tab and toggle off JWT verification. Or redeploy with supabase functions deploy YOUR_FUNCTION_NAME --no-verify-jwt.
  2. Do not turn the check off and leave the function open if it reads or writes private data. Supabase says that with verify_jwt off, your handler is responsible for authenticating the caller. For a signed-in user, their securing guide uses withSupabase from npm:@supabase/server. For a webhook, verify the provider's signature in the handler.

How to check it worked

  • The webhook delivery is no longer 401. A Stripe event shows a 2xx on the function, and the function logs show your code ran.
  • A call with no Authorization header still gets 401 on any function where you left verify_jwt on.
  • A signed-in call through supabase.functions.invoke returns the function's real response.

Sources

More Supabase Edge Functions fixes

Keep going on your own.

The guides stay free. A deep leak report is $15. Fix packs are $24, or $49 for all three. There is no done-for-you repair.

See products