mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(self-hosted): add api gateway logic for functions (#46810)
This commit is contained in:
1 parent
904e3c4aa0
commit
c8b665caf2
9 files changed
+284
-13
No files matched your search
@@ -326,10 +326,11 @@ To change the database password, read [Changing database password](#changing-dat
|
||||
|
||||
## Accessing Edge Functions
|
||||
|
||||
Edge Functions live in `volumes/functions`. The default setup includes a `hello` function you can invoke with `curl`:
|
||||
Edge Functions live in `volumes/functions`. The default setup includes a `hello` function you can invoke with `curl`. It requires your publishable or secret key in the `apikey` header:
|
||||
|
||||
```sh
|
||||
curl http://<your-domain>:8000/functions/v1/hello
|
||||
curl http://<your-domain>:8000/functions/v1/hello \
|
||||
--header 'apikey: <SUPABASE_PUBLISHABLE_KEY>'
|
||||
```
|
||||
|
||||
Add new functions at `volumes/functions/<FUNCTION_NAME>/index.ts`, then restart the service to pick them up:
|
||||
|
||||
@@ -113,7 +113,7 @@ Routes are matched in the order declared. The first matching prefix wins. Protec
|
||||
| `/.well-known/oauth-authorization-server` | auth | - | Open | OAuth 2.0 Authorization Server Metadata (RFC 8414) |
|
||||
| `/auth/v1/sso/saml/acs` | auth | `/sso/saml/acs` | Open | SAML assertion consumer |
|
||||
| `/auth/v1/sso/saml/metadata` | auth | `/sso/saml/metadata` | Open | SAML metadata |
|
||||
| `/functions/v1/` | functions | `/` | Bypass | Edge Functions runtime performs its own JWT verification; 150s timeout |
|
||||
| `/functions/v1/` | functions | `/` | `sb_` keys | Rejects invalid and conflicting `sb_` keys; others pass; timeout: 150s |
|
||||
| `/storage/v1/` | storage | `/` | Bypass | Storage performs its own authorization |
|
||||
| `/auth/v1/` | auth | `/` | API key | Protected Auth endpoints |
|
||||
| `/rest/v1/` | rest | `/` | API key | PostgREST Open API root (requires secret key) |
|
||||
@@ -154,7 +154,7 @@ A Lua filter rejects missing or invalid keys with HTTP `401 Unauthorized`. An RB
|
||||
|
||||
### Opaque key translation
|
||||
|
||||
When the new API keys (`sb_publishable_*`, `sb_secret_*`) are configured, a chain of Lua filters translates opaque keys into the corresponding pre-signed internal JWTs before the request reaches API key enforcement and upstream services. **The entire chain is skipped on `/functions/v1/`**: the Edge Runtime receives the original `apikey` and `Authorization` headers unchanged.
|
||||
When the new API keys (`sb_publishable_*`, `sb_secret_*`) are configured, a chain of Lua filters translates opaque keys into the corresponding pre-signed internal JWTs before the request reaches API key enforcement and upstream services. **The chain is skipped on `/functions/v1/`**, which has its own filter. See [Edge Functions](#edge-functions).
|
||||
|
||||
The chain operates in this order:
|
||||
|
||||
@@ -166,6 +166,23 @@ The chain operates in this order:
|
||||
|
||||
For background on opaque vs asymmetric keys, see [New API Keys and Asymmetric Authentication](/docs/guides/self-hosting/self-hosted-auth-keys).
|
||||
|
||||
### Edge Functions
|
||||
|
||||
On `/functions/v1/`, a dedicated Lua filter handles API keys without changing the `apikey` or `Authorization` headers. When the new API keys are configured, it works as follows:
|
||||
|
||||
| Request | Result |
|
||||
| ------------------------------------------------------------------ | -------------------------------------------------------- |
|
||||
| No `apikey` or `Authorization` | Passed through |
|
||||
| `apikey` is `sb_publishable_*` or `sb_secret_*` | Passed through with `sb-api-key` set to the internal JWT |
|
||||
| `Authorization: Bearer sb_...` and no `apikey` | Same as above, using the key from `Authorization` |
|
||||
| Non-`sb_` value (legacy API key, user session token, any other) | Passed through |
|
||||
| Unknown `sb_` key | Rejected with `401 Unauthorized` |
|
||||
| `apikey` and `Authorization: Bearer sb_...` contain different keys | Rejected with `401 Unauthorized` |
|
||||
|
||||
The filter always removes any `sb-api-key` header sent by the client. Without the new API keys configured, all other requests pass through unchanged. The `sb-api-key` value is the raw JWT, without a `Bearer` prefix. The `apikey` query parameter is not read on this route.
|
||||
|
||||
When `FUNCTIONS_VERIFY_JWT` is `true`, the functions service verifies the JWT in `Authorization`. If `Authorization` is missing or contains an `sb_` key, it verifies `sb-api-key` instead. It removes `sb-api-key` before the request reaches your function. Functions can also check API keys themselves, for example with `withSupabase` from `@supabase/server`. See [Self-hosted Edge Functions](/docs/guides/self-hosting/self-hosted-functions).
|
||||
|
||||
## Forwarded headers and CORS
|
||||
|
||||
### X-Forwarded headers
|
||||
|
||||
@@ -42,7 +42,7 @@ Add the following code to `index.ts`:
|
||||
import { withSupabase } from '@supabase/server'
|
||||
|
||||
export default {
|
||||
fetch: withSupabase({ auth: 'none' }, async (req) => {
|
||||
fetch: withSupabase({ auth: ['publishable', 'secret'] }, async (req) => {
|
||||
const { name } = await req.json()
|
||||
const message = `Hello, ${name}!`
|
||||
|
||||
@@ -51,7 +51,7 @@ export default {
|
||||
}
|
||||
```
|
||||
|
||||
The `auth` option controls who can call the function: `'none'` accepts every request, `'user'` requires a valid user JWT, and `'publishable'` / `'secret'` require an API key. See the [Edge Functions auth guide](/docs/guides/functions/auth) for details.
|
||||
The `auth` option controls who can call the function. This example matches the default `hello` function and requires a publishable or secret API key in the `apikey` header. `'none'` accepts every request, and `'user'` requires a valid user JWT. See the [Edge Functions auth guide](/docs/guides/functions/auth) for details.
|
||||
|
||||
### Step 2: Restart the functions service to pick up the new function
|
||||
|
||||
@@ -63,6 +63,7 @@ sh run.sh restart functions
|
||||
|
||||
```sh
|
||||
curl -X POST http://<your-domain>/functions/v1/my-function \
|
||||
-H 'apikey: <SUPABASE_PUBLISHABLE_KEY>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"name": "World"}'
|
||||
```
|
||||
@@ -226,7 +227,8 @@ Common causes: syntax errors in your function code, invalid imports, or missing
|
||||
### 401 "invalid JWT"
|
||||
|
||||
- Check that `FUNCTIONS_VERIFY_JWT` matches your intent (`true` or `false`) in `.env`
|
||||
- If verification is enabled, ensure you're passing a valid token: `Authorization: Bearer <anon_key or service_role_key>`
|
||||
- If verification is enabled, pass either a valid JWT in `Authorization: Bearer <token>` (a user session token or a legacy API key), or an `sb_publishable_*` or `sb_secret_*` key in the `apikey` header. The API gateway translates `sb_` keys to an internal JWT, which the functions service then verifies.
|
||||
- Verifying asymmetric JWTs, including translated `sb_` keys, requires `SUPABASE_JWKS` to be set for the `functions` service in `docker-compose.yml`. See [New API Keys and Asymmetric Authentication](/docs/guides/self-hosting/self-hosted-auth-keys).
|
||||
|
||||
### Changes to function code not reflected after editing
|
||||
|
||||
|
||||
Reference in new issue
Block a user