From f5f897a29b0f2da952867e36b4017bf0b30e2252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Barroso?= Date: Fri, 28 Aug 2026 12:32:30 +0200 Subject: [PATCH] feat(functions): inject env var function slug (#49617) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Feature (self-hosted Edge Functions) ## What is the current behavior? The self-hosted Edge Functions router (`docker/volumes/functions/main/index.ts`) doesn't tell a function which slug a request resolved to. As a result, `@supabase/server`'s `withOAuthProtectedResource` can't derive its canonical resource URL and falls back to reconstructing it from the request path against the internal `api-gw` origin, so the advertised OAuth Protected Resource is /wrong for self-hosted deployments. ## What is the new behavior? `main/index.ts` now injects `SUPABASE_FUNCTION_SLUG: service_name` per request (after the `Deno.env.toObject()` snapshot, so nothing in the container env can shadow it). Combined with the operator's `SUPABASE_PUBLIC_URL`, the advertised resource is the correct external `{SUPABASE_PUBLIC_URL}/functions/v1/{slug}`, not the internal `http://api-gw:8000`. Verified on the docker stack: the slug is injected per-function, the resource origin resolves to `SUPABASE_PUBLIC_URL`, and the `401` `www-authenticate` carries the right `resource_metadata`. ## Additional context Fixes AI-1128 Companion to `@supabase/server` [PR #117](https://github.com/supabase/server/pull/117) and the [CLI slug injection](https://github.com/supabase/cli/pull/6345) ## Summary by CodeRabbit * **Bug Fixes** * Edge workers now receive the correct function slug in their runtime environment, improving per-function request handling. --- docker/volumes/functions/main/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docker/volumes/functions/main/index.ts b/docker/volumes/functions/main/index.ts index 8d00102c0ec..fee63d44e75 100644 --- a/docker/volumes/functions/main/index.ts +++ b/docker/volumes/functions/main/index.ts @@ -151,7 +151,10 @@ Deno.serve(async (req: Request) => { // Using a common Import Map for all functions // to use a scope 'deno.json' it must be dinamically resolved base on the 'service_name' const importMapPath = `/home/deno/functions/deno.jsonc` - const envVarsObj = Deno.env.toObject() + // SUPABASE_FUNCTION_SLUG is listed after the container env snapshot so + // nothing in it can shadow the value, and it is per-request because only this + // worker knows which function the request resolved to. + const envVarsObj = { ...Deno.env.toObject(), SUPABASE_FUNCTION_SLUG: service_name } const envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]]) try {