mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix(examples): read new API keys directly from parsed SUPABASE_SECRET_KEYS (#46604)
## Problem
Edge Function examples that use the new publishable/secret API keys read
them with a double lookup:
```ts
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
const secretKey = Deno.env.get(SUPABASE_SECRET_KEYS['default']) // ❌ returns undefined
```
`SUPABASE_SECRET_KEYS` / `SUPABASE_PUBLISHABLE_KEYS` are a JSON object
that maps a key name to the **actual key value** (e.g.
`{"default":"sb_secret_..."}`), confirmed by:
- the self-hosted injection in `docker/docker-compose.yml`
(`SUPABASE_SECRET_KEYS: "{\"default\":\"${SUPABASE_SECRET_KEY:-}\"}"`)
- the `@supabase/server` SDK README
So `SUPABASE_SECRET_KEYS['default']` is already the key. Wrapping it in
another `Deno.env.get(...)` looks up an env var named `sb_secret_...`,
which doesn't exist, so the value is `undefined` and the examples fail
at runtime.
## Fix
Unwrap the outer `Deno.env.get(...)` so the key is read directly:
```ts
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
const secretKey = SUPABASE_SECRET_KEYS['default'] // ✅
```
Applied across 23 files (example functions, the
`examples/prompts/edge-functions.md` codegen guidance, and two docs
guides). The correct `JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)`
declaration line is untouched. The generated `apps/docs/examples/` copy
regenerates from `examples/` at build time.
## Notes
- Docs context:
[#46600](https://github.com/supabase/supabase/pull/46600), which
documents the same key model.
- Follow-up (not in this PR): a few examples send the secret key on the
`Authorization: Bearer` header, which the new keys reject. Worth a
separate audit.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Clarified examples and guides for correctly reading parsed Supabase
secret and publishable key maps.
* **Examples**
* Standardized credential usage across Edge Functions and samples so
Supabase clients consistently receive keys from the parsed key maps
rather than indirect lookups.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Chris Chinchilla <chris.ward@supabase.io>
This commit is contained in:
1 parent
c582d3749c
commit
e3be344f5c
23 files changed
+23
-35
No files matched your search
@@ -65,7 +65,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default when deployed.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API SECRET KEY - env var exported by default when deployed.
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) ?? ''
|
||||
SUPABASE_SECRET_KEYS['default'] ?? ''
|
||||
)
|
||||
|
||||
// Construct image url from storage
|
||||
|
||||
@@ -120,7 +120,7 @@ const elevenLabsClient = new ElevenLabsClient({
|
||||
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL') || '',
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) || ''
|
||||
SUPABASE_SECRET_KEYS['default'] || ''
|
||||
)
|
||||
|
||||
async function scribe({
|
||||
|
||||
@@ -58,7 +58,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default.
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
// Supabase API SECRET KEY - env var exported by default.
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
SUPABASE_SECRET_KEYS['default']!
|
||||
)
|
||||
|
||||
const { data: upload, error: uploadError } = await supabaseClient.storage
|
||||
|
||||
@@ -15,7 +15,7 @@ const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
|
||||
const supabase = createClient<Database>(
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
SUPABASE_SECRET_KEYS['default']!
|
||||
)
|
||||
|
||||
const model = new Supabase.ai.Session('gte-small')
|
||||
|
||||
@@ -7,7 +7,7 @@ const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
|
||||
const supabase = createClient<Database>(
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
SUPABASE_SECRET_KEYS['default']!
|
||||
)
|
||||
|
||||
const model = new Supabase.ai.Session('gte-small')
|
||||
|
||||
@@ -4,10 +4,7 @@ import OpenAI from 'https://deno.land/x/openai@v4.68.2/mod.ts'
|
||||
const client = new OpenAI({ apiKey: Deno.env.get('OPENAI_API_KEY')! })
|
||||
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
)
|
||||
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default']!)
|
||||
|
||||
type StorageFileApi = ReturnType<typeof supabase.storage.from>
|
||||
type StorageUploadPromise = ReturnType<StorageFileApi['upload']>
|
||||
|
||||
@@ -19,7 +19,7 @@ const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL') || '',
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) || ''
|
||||
SUPABASE_SECRET_KEYS['default'] || ''
|
||||
)
|
||||
|
||||
async function scribe({
|
||||
|
||||
@@ -5,10 +5,7 @@ import { ElevenLabsClient } from 'npm:elevenlabs@1.52.0'
|
||||
import * as hash from 'npm:object-hash'
|
||||
|
||||
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
)
|
||||
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default']!)
|
||||
|
||||
const client = new ElevenLabsClient({
|
||||
apiKey: Deno.env.get('ELEVENLABS_API_KEY'),
|
||||
|
||||
@@ -29,7 +29,7 @@ app.use(async (ctx) => {
|
||||
// Supabase API URL - env var exported by default.
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
// Supabase publishable key - env var exported by default.
|
||||
Deno.env.get(SUPABASE_PUBLISHABLE_KEYS['default'])!
|
||||
SUPABASE_PUBLISHABLE_KEYS['default']!
|
||||
)
|
||||
|
||||
//upload image to Storage
|
||||
|
||||
@@ -61,7 +61,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default when deployed.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API SECRET KEY - env var exported by default when deployed.
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) ?? ''
|
||||
SUPABASE_SECRET_KEYS['default'] ?? ''
|
||||
)
|
||||
// Submit email to draw
|
||||
const { error } = await supabaseAdminClient.from('get-tshirt-competition-2').upsert(
|
||||
|
||||
@@ -23,7 +23,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default when deployed.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API SECRET KEY - env var exported by default when deployed.
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) ?? ''
|
||||
SUPABASE_SECRET_KEYS['default'] ?? ''
|
||||
)
|
||||
|
||||
// Construct image url from storage
|
||||
|
||||
@@ -201,7 +201,7 @@ export async function handler(req: Request) {
|
||||
// Supabase API URL - env var exported by default when deployed.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API SECRET KEY - env var exported by default when deployed.
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) ?? ''
|
||||
SUPABASE_SECRET_KEYS['default'] ?? ''
|
||||
)
|
||||
|
||||
// Upload image to storage.
|
||||
|
||||
@@ -85,7 +85,7 @@ Deno.serve(async (req) => {
|
||||
// Upload the generated image to Supabase Storage
|
||||
const supabaseClient = createClient(
|
||||
Deno.env.get('SUPABASE_URL') || '',
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) || ''
|
||||
SUPABASE_SECRET_KEYS['default'] || ''
|
||||
)
|
||||
|
||||
// Create a unique identifier for this generation
|
||||
|
||||
@@ -25,7 +25,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API publishable key - env var exported by default.
|
||||
Deno.env.get(SUPABASE_PUBLISHABLE_KEYS['default']) ?? '',
|
||||
SUPABASE_PUBLISHABLE_KEYS['default'] ?? '',
|
||||
// Create client with Auth context of the user that called the function.
|
||||
// This way your row-level-security (RLS) policies are applied.
|
||||
{
|
||||
|
||||
@@ -82,7 +82,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase publishable key - env var exported by default.
|
||||
Deno.env.get(SUPABASE_PUBLISHABLE_KEYS['default']) ?? '',
|
||||
SUPABASE_PUBLISHABLE_KEYS['default'] ?? '',
|
||||
// Create client with Auth context of the user that called the function.
|
||||
// This way your row-level-security (RLS) policies are applied.
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ Deno.serve(async (req: Request) => {
|
||||
// Supabase API URL - env var exported by default.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API PUBLISHABLE KEY - env var exported by default.
|
||||
Deno.env.get(SUPABASE_PUBLISHABLE_KEYS['default']) ?? '',
|
||||
SUPABASE_PUBLISHABLE_KEYS['default'] ?? '',
|
||||
// Create client with Auth context of the user that called the function.
|
||||
// This way your row-level-security (RLS) policies are applied.
|
||||
{
|
||||
|
||||
@@ -9,10 +9,7 @@ import * as Sentry from 'https://deno.land/x/sentry@7.102.0/index.mjs'
|
||||
|
||||
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
)
|
||||
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default']!)
|
||||
|
||||
Sentry.init({
|
||||
dsn: Deno.env.get('SENTRY_DSN'),
|
||||
|
||||
@@ -70,7 +70,7 @@ export async function handler(req: Request) {
|
||||
// Supabase API URL - env var exported by default when deployed.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase API SECRET KEY - env var exported by default when deployed.
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default']) ?? ''
|
||||
SUPABASE_SECRET_KEYS['default'] ?? ''
|
||||
)
|
||||
|
||||
// Upload image to storage.
|
||||
|
||||
@@ -12,7 +12,7 @@ Deno.serve(async (req) => {
|
||||
// Supabase API URL - env var exported by default.
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
// Supabase publishable key - env var exported by default.
|
||||
Deno.env.get(SUPABASE_PUBLISHABLE_KEYS['default']) ?? '',
|
||||
SUPABASE_PUBLISHABLE_KEYS['default'] ?? '',
|
||||
// Create client with Auth context of the user that called the function.
|
||||
// This way your row-level-security (RLS) policies are applied.
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ You're an expert in writing TypeScript and Deno JavaScript runtime. Generate **h
|
||||
- SUPABASE_SECRET_KEYS
|
||||
- SUPABASE_DB_URL
|
||||
|
||||
You then need to use `JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)` or `JSON.parse(Deno.env.get('SUPABASE_PUBLISHABLE_KEYS')!)` to access the actual keys in the code. For example, `Deno.env.get(SUPABASE_SECRET_KEYS['default'])` to access the default service key. 9. To set other environment variables (ie. secrets) users can put them in a env file and run the `supabase secrets set --env-file path/to/env-file` 10. A single Edge Function can handle multiple routes. It is recommended to use a library like Express or Hono to handle the routes as it's easier for developer to understand and maintain. Each route must be prefixed with `/function-name` so they are routed correctly. 11. File write operations are ONLY permitted on `/tmp` directory. You can use either Deno or Node File APIs. 12. Use `EdgeRuntime.waitUntil(promise)` static method to run long-running tasks in the background without blocking response to a request. Do NOT assume it is available in the request / execution context.
|
||||
You then need to parse them with `JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)` or `JSON.parse(Deno.env.get('SUPABASE_PUBLISHABLE_KEYS')!)` to access the actual keys in the code. For example, assign the parsed map first with `const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)` and then index it with `SUPABASE_SECRET_KEYS['default']` to access the default secret key. 9. To set other environment variables (ie. secrets) users can put them in a env file and run the `supabase secrets set --env-file path/to/env-file` 10. A single Edge Function can handle multiple routes. It is recommended to use a library like Express or Hono to handle the routes as it's easier for developer to understand and maintain. Each route must be prefixed with `/function-name` so they are routed correctly. 11. File write operations are ONLY permitted on `/tmp` directory. You can use either Deno or Node File APIs. 12. Use `EdgeRuntime.waitUntil(promise)` static method to run long-running tasks in the background without blocking response to a request. Do NOT assume it is available in the request / execution context.
|
||||
|
||||
## Example Templates
|
||||
|
||||
|
||||
@@ -27,6 +27,6 @@ Deno.serve((req) => {
|
||||
const { method, headers } = req
|
||||
// Add Auth header
|
||||
const modHeaders = new Headers(headers)
|
||||
modHeaders.append('authorization', `Bearer ${Deno.env.get(SUPABASE_SECRET_KEYS['default'])!}`)
|
||||
modHeaders.append('authorization', `Bearer ${SUPABASE_SECRET_KEYS['default']!}`)
|
||||
return fetch(url, { method, headers: modHeaders })
|
||||
})
|
||||
+1
-1
@@ -5,7 +5,7 @@ const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
const SUPABASE_URL = Deno.env.get('SUPABASE_URL') ?? ''
|
||||
const SUPABASE_SECRET_KEY = Deno.env.get(SUPABASE_SECRET_KEYS['default']) ?? ''
|
||||
const SUPABASE_SECRET_KEY = SUPABASE_SECRET_KEYS['default'] ?? ''
|
||||
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_SECRET_KEY)
|
||||
|
||||
|
||||
@@ -20,10 +20,7 @@ interface WebhookPayload {
|
||||
}
|
||||
|
||||
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL')!,
|
||||
Deno.env.get(SUPABASE_SECRET_KEYS['default'])!
|
||||
)
|
||||
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default']!)
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
const payload: WebhookPayload = await req.json()
|
||||
|
||||
Reference in new issue
Block a user