Supabase middleware pipeline: verify a Sume webhook first

Put Sume's verifyWebhook in the first step of a Supabase middleware pipeline: return 401 on a bad signature and handlers only see verified events.

4 min readSume
All posts

Make signature verification the first step of the pipeline. Read the raw body, call Sume's verifyWebhook, and return a 401 Response when it fails. Supabase's changelog says any middleware can return a Response and stop the chain, so later steps and your handler only ever see events that passed.

Supabase's side is from its changelog entry for Supabase Middleware 1.0 (read 2026-09-30). Sume's side is from Verifying webhooks. I did not read the package's API reference, so the code below is a plain Fetch-style step you wrap with defineMiddleware yourself.

What does the Supabase changelog say about the pipeline?

The changelog says @supabase/middleware 1.0.0 is on npm and JSR. defineMiddleware writes one piece of per-request logic, pipeline([...], handler) runs several in order, and the engine runs wherever fetch runs, including Supabase Edge Functions, Vercel Functions, Cloudflare Workers, Deno, Bun and Node 22 or newer. A middleware can read and change the response on the way out, or return one and stop the chain.

What must the verify step do?

Sume webhook handling rules from the docs, read 2026-09-30: https://docs.sume.com/sdk/webhooks
RuleWhat the docs say
BodyRead it raw with request.text() before any JSON.parse
SecretSUME_COM_WEBHOOK_SIGNING_SECRET
Failed checkReturn 401 with a short body
RoutingOne verifier covers run and job events; route on event
Unknown eventReturn 204, not a 500 and a retry storm

What does the step look like?

The step returns the body to continue, or a Response to stop. The verified body goes onward as text so the next step parses it once.

import { verifyWebhook } from "@sume-com/sdk";

export async function verifySume(
  request: Request,
  secret: string,
): Promise<{ body: string } | Response> {
  const body = await request.text(); // raw, before any JSON.parse
  const ok = await verifyWebhook({ body, headers: request.headers, secret });
  if (!ok) return new Response("bad signature", { status: 401 });
  return { body };
}

export function routeSume(body: string): Response {
  const event = JSON.parse(body);
  switch (event.event) {
    case "job.completed":
    case "job.failed":
      return new Response(null, { status: 204 });
    default:
      return new Response(null, { status: 204 }); // unknown event
  }
}

How do I wire it into the pipeline?

Wrap verifySume in defineMiddleware so it contributes the verified body to the shared context, and place it first. Order matters: Supabase says a middleware placed before its prerequisite fails to compile. Put any other steps after it.

What should the handler do after verification?

Dedupe on job_id for job events (the docs dedupe run events on request_id) and return a fast 2xx, then do the work. Sume makes up to 10 delivery attempts in total and a failed delivery is not a failed job, so also keep status polling as a backup. Supabase edge function video webhook covers the handler side.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume