Const Alphaimport { pipeline } from '@supabase/middleware'
import { withClaims } from '@supabase/server/middleware/claims'
import { withPostgresClient } from '@supabase/server/middleware/postgres'
export default {
fetch: pipeline([withClaims(), withPostgresClient()], async (req, ctx) => {
const rows = await ctx.postgres.query`select id, title from posts`
return Response.json({ rows, caller: ctx.jwtClaims?.sub ?? 'anon' })
}),
}
The composable middleware surface tracks @supabase/middleware 0.x — entry
shapes, context keys, and config options may change between 0.x releases.
Alpha. Contributes
ctx.jwtClaimsby verifying the caller's Bearer token against the project JWKS — the same verification corewithSupabaseuses for itsuserauth mode.Use this when composing a standalone
pipeline([...], handler)that is not wrapped bywithSupabase— for example a Supabase-agnostic Edge Function that still wants the caller's verified claims available to a downstream middleware such aswithPostgresClient. InsidewithSupabase, the context already carriesjwtClaims, sowithClaimsis unnecessary.Behavior:
Authorization: Bearertoken (or ansb_*API key in that position) → contributesnull; the request proceeds as anonymous.{ message, code }, matchingwithSupabase's error shape).withClaimsis not an auth gate. It never rejects a request that has no token. A pipeline like[withClaims(), withSupabaseClient()]accepts anonymous callers and is not the composable form ofwithSupabase({ auth: 'user' }), which rejects token-less requests with a 401. To require an authenticated caller, composewithRequiredClaimsfrom@supabase/server/middleware/required-claimsinstead. The two entries share thejwtClaimskey, so a pipeline picks "claims if present" or "claims required"; composing both is a compile-time conflict.