Basi della sicurezza
Nascondere una chiave API: spostala in una Edge Function Supabase
Nascondere una chiave API vuol dire toglierla dal browser, e una Edge Function Supabase è il posto più piccolo dove metterla. Due passaggi contano di più.

In breve
- Niente nel browser sa tenere un segreto, quindi nascondere una chiave API vuol dire spostarla dove si può. Una Edge Function Supabase è il server più piccolo che puoi avere.
- Lo spostamento sono quattro passaggi. Sostituisci prima la chiave che hai già pubblicato, perché la copia nel tuo vecchio bundle resta leggibile anche dopo che la togli.
- Una function in produzione pretende un token di default, e la chiave pubblica del tuo stesso frontend soddisfa quella pretesa. Controllare chi sta chiamando è un passaggio a parte, ed è quello che impedisce a uno sconosciuto di consumare la tua quota.
Ogni guida su una chiave API finita in giro si chiude allo stesso punto: spostala su un server. Poi si ferma. Ti resta un'app costruita in Lovable, Bolt o Cursor, nessun server all'orizzonte, e una frase che dà per scontato che tu sappia già cosa fare dopo.
Ecco la parte che guida dopo guida lascia fuori. Spostare la chiave in una Edge Function Supabase la toglie dalla tua pagina, e da solo questo non impedisce a uno sconosciuto di usarla. La documentazione di Supabase dice perché: il controllo che una function in produzione esegue di default accetta anche la tua chiave pubblica, e la tua chiave pubblica sta nel tuo frontend, a disposizione di chi voglia copiarla. Nascondere la chiave è la metà semplice. Dell'altra metà non scrive nessuno: decidere a chi risponde la tua nuova function.
Pensa alla chiave come al passe-partout di un magazzino. Adesso è attaccato dentro la vetrina, dove lo legge chiunque si fermi. Una Edge Function è un retrobottega con uno sportello: la chiave va lì dentro, e i visitatori chiedono allo sportello invece di entrare e servirsi. Che sia un miglioramento dipende da per chi si apre lo sportello.
Dove metto la mia chiave API, se non nel frontend?
Ovunque tranne il browser. Una Edge Function è la versione più piccola di quel posto.
Un browser non sa tenere un segreto. Tutto quello che serve alla tua pagina per
funzionare viene scaricato da ogni visitatore, e un visitatore può leggerlo
tutto: il codice, le immagini, i valori compilati dentro il codice. Non è un
difetto del tuo strumento. È quello che è una pagina web.
Quali chiavi API sono sicure nel frontend
è la versione lunga; quella corta è che una chiave sk_, una chiave OpenAI o una
chiave segreta Supabase non sarebbe mai sopravvissuta a un viaggio nel browser.
Una Edge Function Supabase è un piccolo pezzo di codice che gira sulle macchine di Supabase. Può leggere i segreti che hai impostato sul progetto, risponde a un indirizzo web tutto suo, e la tua app la chiama per nome. Scrivi un file, Supabase lo esegue, e non c'è nessun server da affittare, aggiornare o tenere sveglio.
Sostituisci la chiave già pubblicata, prima di spostare qualsiasi cosa
La chiave che oggi sta nel tuo frontend è già pubblica, e resta pubblica dopo che la togli dal codice.
Ogni visitatore che ha caricato il tuo sito l'ha scaricata. Ogni crawler pure, e ce ne sono di automatici che percorrono tutto il web cercando esattamente queste stringhe. Il tuo vecchio bundle sta inoltre ancora nella tua cronologia delle versioni e in ogni cache che ha una copia della tua pagina. Cancellare una riga da un file che controlli non cambia niente su un valore già distribuito.
Quindi l'ordine è: creare una chiave nuova dal fornitore, tenerla da parte un momento, e revocare la vecchia appena la function qui sotto è attiva. Poi leggi la tua pagina di fatturazione e i log dei consumi per tutto il periodo in cui la vecchia chiave è stata fuori. Sostituirla ferma quello che viene; su quello che è già successo non ha nessun effetto. Se la chiave era una chiave segreta Supabase, l'ordine in cui lavorare ha una sfumatura che conviene leggere prima.
I quattro passaggi
Salva il segreto, scrivi la function, mettila in produzione, poi cambia la tua app perché chiami la function invece del fornitore.
| Passaggio | Da riga di comando | Nella dashboard |
|---|---|---|
| 1. Salvare il segreto | supabase secrets set MY_API_KEY=… | Edge Functions → Secrets, poi Key e Value |
| 2. Scrivere la function | supabase functions new forward-request | Edge Functions → Deploy a new function → Via Editor |
| 3. Metterla in produzione | supabase functions deploy | Il bottone Deploy sotto l'editor |
| 4. Chiamarla dalla tua app | supabase.functions.invoke('…') | Uguale, nel codice della tua app |
Dentro la function il segreto arriva come variabile di ambiente, cioè un valore con un nome che il codice può leggere e nessuno da fuori. La documentazione Supabase sui segreti delle Edge Functions ha il riferimento completo, e tre dettagli lì dentro risparmiano un'ora di confusione:
- Il nome di un segreto non può iniziare con
SUPABASE_. Quel prefisso è riservato ai valori che Supabase imposta per te, e lo rifiutano sia la dashboard sia l'API. - Un segreto nuovo è leggibile subito. Non devi rimettere in produzione la function dopo averne cambiato uno.
- Locale e produzione sono separati. Lo stack locale legge
supabase/functions/.env, che è un posto diverso dai segreti del tuo progetto attivo, quindi imposta il valore in entrambi, altrimenti la function funziona sulla tua macchina e fallisce una volta in produzione.
Poi cancella la vecchia variabile dal tuo frontend. Se si chiamava VITE_,
NEXT_PUBLIC_ o EXPO_PUBLIC_, quel prefisso era l'istruzione di compilare il
valore dentro il bundle, e il prefisso è tutta la
storia di come ci è finito.
Se serve un token, vuol dire che chiamano solo i miei utenti?
No, ed è il punto di questo articolo che vale due letture.
Supabase attiva di default un controllo chiamato verify_jwt. Guarda
l'intestazione Authorization prima che il tuo codice parta e rifiuta la
richiesta se lì non c'è niente di valido. Sembra una porta che aprono solo i tuoi
utenti. Non lo è, perché Supabase documenta anche che lo stesso controllo
accetta una chiave pubblica o segreta
su entrambe le intestazioni, per compatibilità con i progetti più vecchi, e
aggiunge chiaramente che il controllo da solo non autentica chi chiama mandando
soltanto una chiave API.
La tua chiave pubblica sta nel tuo frontend. È corretto ed è pensata per stare lì. Vuol dire però anche che chi apre il tuo sito, legge la chiave e la manda alla tua nuova function passa il controllo della piattaforma ed entra nel tuo codice.
Nel magazzino, verify_jwt è un portiere che controlla che tu abbia un pass da
visitatore. Ce l'ha ogni visitatore, perché li distribuisci tu all'ingresso. Chi
sta allo sportello fa un altro mestiere, ed è quello che chiede quale visitatore
sei.
Chiudere la function, per non aver costruito un proxy aperto
Decidi quali chiamanti accetta la tua function, e scrivi quella decisione dentro la function.
Supabase fornisce un wrapper per questo, quindi è una riga e non un progetto.
Metti auth: 'user' e la function accetta il token di un utente autenticato e
passa al tuo codice un client di database già limitato alle regole di Row Level
Security di quell'utente:
import { withSupabase } from 'npm:@supabase/server@1'
export default {
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
// ctx.userClaims dice chi sta chiamando. Rifiuta qui quello che non vuoi,
// poi chiama il fornitore con il segreto preso dall'ambiente.
return Response.json({ ok: true })
}),
}
La pagina Securing Edge
Functions elenca gli altri
modi, e due contano per un'app normale. Una function chiamata da un'altra
macchina invece che da un browser usa auth: 'secret', con la chiave segreta
mandata nell'intestazione apikey. Una function che riceve webhook da Stripe o
da GitHub non può usare nessuno dei due, perché quei fornitori non hanno nessun
token tuo; mette verify_jwt = false e verifica la firma del fornitore dentro
l'handler.
Qualunque cosa tu scelga, decidi con cura cosa succede quando arriva un chiamante che non ti aspettavi. L'esempio che fa Supabase di una function che può accettare chiunque è un controllo di stato, e un controllo di stato non costa niente quando lo chiama uno sconosciuto. Una function che inoltra una chiamata API a pagamento te la fattura una per una.
Posso usare service_role in una Edge Function?
Sì. Una function è l'unico posto in cui una chiave segreta Supabase ha senso.
E non devi nemmeno incollarla. Supabase mette le chiavi del progetto
nell'ambiente della function, quindi il codice le legge da lì e non da un segreto
impostato da te. I progetti nuovi ricevono SUPABASE_SECRET_KEYS e
SUPABASE_PUBLISHABLE_KEYS, ciascuno un piccolo dizionario di chiavi con nome; i
progetti più vecchi ricevono SUPABASE_SERVICE_ROLE_KEY e SUPABASE_ANON_KEY
con i loro nomi di sempre. Cos'è cambiato quando Supabase ha rinominato le sue
chiavi ti dice quale coppia hai.
Usa la chiave segreta per il lavoro che deve davvero vedere ogni riga, per esempio scrivere una traccia che l'utente non possa modificare. Per tutto quello che un utente legge su di sé, usa il suo token e lascia filtrare le tue regole di Row Level Security, che servono a quello.
Verificarlo dal browser, l'unica prova che conta
Carica il tuo sito attivo, apri la scheda di rete, e guarda cosa manda davvero il tuo browser.
Le due cose da controllare:
- Nessuna richiesta porta la chiave. Percorri la parte della tua app che
prima chiamava il fornitore. La richiesta in uscita deve andare a
…supabase.co/functions/v1/la-tua-function, e l'unica credenziale lì dentro deve essere la tua chiave pubblica o il token del tuo utente. - La chiave non sta nel codice scaricato. Usa la ricerca del browser su tutti i file caricati e incolla la prima dozzina di caratteri della vecchia chiave. Nessun risultato è la risposta che vuoi.
Solo una ricompilazione e una nuova messa in produzione tolgono un valore dal bundle. Una chiave che compare ancora nella ricerca di solito vuol dire che il frontend è uscito prima che ne uscisse la variabile.
La nostra scansione gratuita fa il secondo controllo da fuori e nomina quello che riesce a leggere nel tuo bundle attivo, compresa quale chiave Supabase hai pubblicato. Impiega circa 20 secondi e non serve nessun account: scansiona la tua app.
Come farlo da Lovable, Bolt o Replit
Usa la dashboard di Supabase. Lì dentro non c'è nessun passaggio da terminale.
Apri il tuo progetto, scegli Edge Functions nella barra laterale, poi Deploy a new function → Via Editor. La guida rapida della dashboard di Supabase la percorre con gli screenshot, e tra i modelli che propone ce n'è uno per inoltrare a un fornitore di IA, cioè esattamente la forma di questo lavoro. La messa in produzione impiega tra i dieci e i trenta secondi, e la function resta attiva a un indirizzo tutto suo. Il tuo segreto va sulla pagina Edge Function Secrets, nella stessa sezione.
Un avvertimento da conoscere prima di affidartici: Supabase scrive che l'editor della dashboard non ha controllo di versione, né versioni, né ritorno indietro, e lo consiglia per il lavoro veloce invece che per codice destinato a restare. Premere Deploy sovrascrive quello che c'era. Se la function finisce per fare qualcosa a cui tieni, scaricala da quella pagina e tieni il file da parte.
C'è anche una versione di questa domanda a forma di Replit, perché Replit ha un suo archivio di segreti e la tua app lì esegue un suo server. Cosa fanno davvero i Replit Secrets è quella versione.
Quando una Edge Function è la risposta sbagliata
Due casi, e in tutti e due lo spostamento ti costa lavoro e non porta niente.
La chiave era pubblica per progetto. Una chiave Stripe pk_live_, una chiave
pubblica Supabase o una chiave anon, un token pubblico Mapbox: sono fatte per
stare in un browser, e la protezione sta altrove. Metterne una dietro una
function aggiunge un giro e non toglie nessun rischio. Quali chiavi
sono è l'elenco.
La chiave si può limitare al tuo sito. Le chiavi browser di Google sono l'esempio solito: nella console Google puoi limitarne una ai tuoi domini, ed è proprio la soluzione che Google prevede per questo caso. La chiave resta leggibile e smette di servire a chi la copia.
Tutto il resto sta su un server. Una chiave OpenAI o Anthropic non ha variante pubblica, ed è per questo che una chiave di fornitore di IA nel tuo frontend non ha nessuna impostazione che la salvi, e nessuna minificazione nasconde una chiave segreta Stripe a chi legge la tua pagina.
Cosa fare adesso
Cosa fare
- Sostituisci prima la chiave. Creane una nuova dal fornitore, mettila nel segreto della function, e revoca la vecchia appena la function è attiva.
- Salva il segreto sul tuo progetto Supabase, non nel tuo repository e non in una variabile
VITE_. Impostalo separatamente per lo sviluppo locale e per la produzione. - Metti in produzione una function che usa il segreto, e cambia la tua app perché chiami la function per nome invece del fornitore.
- Aggiungi un controllo su chi sta chiamando.
verify_jwtda solo accetta la chiave pubblica del tuo stesso frontend, quindi non tiene fuori uno sconosciuto. - Cancella la vecchia variabile, ricompila, e conferma nella scheda di rete del browser che niente in uscita porta la chiave.
- Leggi fatturazione e consumi per tutto il periodo in cui la vecchia chiave è stata pubblica. Sostituirla ferma il prossimo addebito e non l'ultimo.
Se preferisci passare in rassegna tutta la tua app invece di una sola chiave, la checklist di sicurezza in 10 minuti copre questo insieme alle altre cose da chiudere in un'app appena lanciata.
FAQ
Dove metto la mia chiave API, se non nel frontend?
Ovunque tranne il browser. Una Edge Function Supabase è l'opzione più piccola: salvi la chiave come segreto sul tuo progetto, scrivi un file piccolo che la usa, e la tua app chiama quella function per nome invece di chiamare il fornitore direttamente. Una rotta serverless dal tuo hosting o un server tuo funzionano allo stesso modo. Quello che hanno in comune è che la chiave viene letta dove il tuo visitatore non la vede.
Che cos'è una Edge Function Supabase?
Un piccolo pezzo di codice che gira sulle macchine di Supabase invece che nel browser del tuo visitatore. Risponde a un indirizzo web tutto suo, può leggere i segreti che hai impostato sul progetto, e la tua app lo chiama con supabase.functions.invoke. Scrivi un file, Supabase lo esegue, e non c'è nessun server da affittare o mantenere.
Devo sostituire la chiave dopo averla spostata?
Sì, e per prima cosa. La chiave che stava nel tuo frontend è stata scaricata da ogni visitatore e da ogni crawler che ha letto il tuo sito, e toglierla dal codice non cambia niente su quelle copie. Crea una chiave nuova dal fornitore, mettila nel segreto della tua Edge Function e revoca la vecchia. Poi controlla fatturazione e consumi per tutto il periodo in cui la vecchia chiave era attiva.
Chiunque può chiamare la mia Edge Function?
Di default una function rifiuta una richiesta senza nessun token, ma quel controllo è più debole di quanto sembri. Supabase documenta che il controllo della piattaforma accetta anche la tua chiave pubblica o segreta, e la tua chiave pubblica sta nel tuo frontend, dove chiunque può leggerla. Quindi il controllo ferma una richiesta vuota e non una decisa. Per accettare solo i tuoi utenti autenticati, verifica chi chiama dentro la function.
Posso usare service_role in una Edge Function?
Sì. Una Edge Function è l'unico posto in cui una chiave segreta Supabase ha senso, e Supabase mette le chiavi del progetto nell'ambiente della function per te, quindi non ne incolli mai una. Usala per il lavoro che deve vedere ogni riga, e usa il token di chi chiama per tutto ciò che deve rispettare le tue regole di Row Level Security.
Posso farlo senza terminale?
Sì. La dashboard di Supabase ha una sezione Edge Functions dove scrivi una function nel browser, premi Deploy e imposti il tuo segreto sulla pagina Edge Function Secrets. Supabase avverte che l'editor della dashboard non tiene nessuna cronologia delle versioni, quindi lo consiglia per il lavoro veloce e lascia la riga di comando per quello che vuoi tenere.