# Geheime API-sleutel in een Expo-app: wat beschermen?

> Publieke Supabase-sleutel, serversecret, Expo-variabelen: ontdek wat in je iPhone-app mag en test de toegang met twee accounts.

Originele pagina: [Geheime API-sleutel in een Expo-app: wat beschermen?](https://devoria.fr/nl/blog/geheime-api-sleutel-expo-app-beschermen)
Auteur: [Mehdi Azizi](https://devoria.fr/nl/mehdi-azizi)
Publicatie: 2026-09-29
Laatste inhoudsrevisie: 2026-10-09


## Een omgevingsvariabele is niet per se een geheim

In een Expo-app is een variabele met het voorvoegsel `EXPO_PUBLIC_` bedoeld voor de code van de app. Er mag geen serversecret in staan. Expo legt uit dat deze waarden in het gecompileerde JavaScript terechtkomen en door gebruikers van de app gelezen kunnen worden. Een sleutel naar een `.env`-bestand verplaatsen is dus niet genoeg om hem te beschermen. [Bron: omgevingsvariabelen in Expo](https://docs.expo.dev/guides/environment-variables/).

Voordat je een AI vraagt om "de API aan te sluiten", deel je in wat je hem geeft: een serviceadres, een sleutel die bedoeld is om publiek te zijn, of een sleutel die geprivilegieerde acties toestaat. Die indeling bepaalt waar de code moet draaien.

De tabel hieronder is een ontwerpraster, geen audit van je app.

| Onderdeel                                          | Waar plaatsen                                | Wat controleren                                                                            |
| -------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Publiek adres van de backend                       | Configuratie van de app                      | Het wijst naar de juiste omgeving.                                                         |
| Supabase publishable-sleutel, of oude anon-sleutel | In de app als de rechten goed zijn ingesteld | De dataregels blokkeren echt de toegang tot het account van een andere gebruiker.          |
| Supabase secret- of service_role-sleutel           | Alleen op de server                          | Hij staat niet in de mobiele bundle en niet in logs die de client kan zien.                |
| Geheime sleutel van een AI-aanbieder               | Alleen op de server                          | De app roept je server aan, die de gebruiker en de limieten controleert vóór de aanbieder. |

Supabase maakt onderscheid tussen sleutels voor clients en geheime sleutels voor vertrouwde omgevingen. Een publieke sleutel identificeert het project; hij vervangt geen rechten op de data. [Bron: API-sleutels van Supabase](https://supabase.com/docs/guides/getting-started/api-keys).

## Voorbeeld: een fictieve leesdagboek-app

Stel je een app voor waarin Léa en Sami hun boeken en privénotities bijhouden. Dit voorbeeld dient om de tests voor te bereiden; het beschrijft geen resultaten van een Devoria-app.

Het normale pad lijkt in orde: Léa logt in en ziet haar notities. Maar daarmee is de belangrijke vraag nog niet beantwoord: weigert de server een verzoek van Léa voor een notitie van Sami?

Een filter in de interface, zoals "toon de notities van de ingelogde gebruiker", verbetert de weergave. De autorisatie moet ook aan de datakant worden afgedwongen. In Supabase kun je met Row Level Security-regels de toegankelijke rijen beperken op basis van de sessie. Supabase raadt aan ze in te schakelen voor tabellen die via de API beschikbaar zijn en legt de lees- en schrijfpolicies uit. [Bron: Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security).

Koppel in je eigen testproject elke notitie aan de eigenaar en bepaal apart wie haar mag lezen, aanmaken, wijzigen en verwijderen. Controleer ook de bestanden: een databaserij beschermen bewijst niet dat een afbeelding privé is.

## Het testscript met twee testaccounts

Maak twee accounts aan die jij beheert, met in elk een ander boek en een kleine herkenbare notitie. Gebruik fictieve data in een toegestane testomgeving.

1. **Eigen notitie lezen.** Account A vindt notitie A terug.
2. **Notitie van B lezen vanuit A.** Het verzoek onthult de privé-inhoud niet.
3. **Notitie van B wijzigen vanuit A.** De server weigert; notitie B blijft ongewijzigd.
4. **Aanmaken namens B vanuit A.** De server weigert die toewijzing.
5. **Lezen zonder sessie.** Er wordt geen privé-inhoud teruggegeven.
6. **Privébestand van B openen vanuit A.** Het bestand is niet toegankelijk.

Noteer het echte resultaat, de geteste versie en een eventuele fout. "De regels staan aan" is geen testresultaat. Het [testraster bij de resources](https://devoria.fr/nl/resources) kun je als basis gebruiken om dat bewijs te bewaren.

## Een betaalde aanroep via je server laten lopen

Voor een functie die een boek samenvat met [een AI-API](https://devoria.fr/nl/blog/guideline-5-1-2-ai-derden-att-data-delen) kan het pad zijn: app → je server → aanbieder → je server → app. De geheime sleutel blijft op de server. Die architectuur alleen is niet genoeg: de toegang tot de server moet ook gecontroleerd worden.

In het fictieve voorbeeld moet de server onder meer de sessie controleren, nagaan of het boek van die persoon is, herhaalde verzoeken beperken en een begrijpelijke fout teruggeven als de aanbieder niet reageert. De client bepaalt niet zelf dat een gebruiker betaalde toegang heeft.

Bereid vier tests voor: niet-ingelogde gebruiker, boek van een ander account, limiet bereikt en aanbieder onbereikbaar. Met de laatste controleer je dat de app uit de laadstatus komt zonder de invoer kwijt te raken.

## Wat je je codeassistent kunt vragen

Hier is een review-instructie om aan te passen aan je repository, zonder je geheime waarden erin te plakken:

> Inventariseer de variabelen die de mobiele code en de server gebruiken, en toon alleen hun namen. Identificeer geprivilegieerde aanroepen aan de clientkant. Beschrijf voor privédata de lees- en schrijfcontroles en stel daarna een testscript met twee testaccounts voor. Voer geen sleutelrotatie of productiewijziging uit zonder goedkeuring.

Lees het antwoord naast de bijbehorende code. Een assistent kan een inconsistentie opmerken; zijn antwoord vervangt het uitvoeren van de tests niet. De gids [een app maken met Claude Code](https://devoria.fr/nl/blog/app-maken-met-claude-code-iphone-tutorial) legt uit hoe je dit werk opdeelt.

## Voordat je verdergaat met je app

Je moet drie dingen eenvoudig kunnen uitleggen: welke waarden publiek zijn, welke bewerkingen via de server lopen en welke tests laten zien dat het ene account de data van het andere niet ziet. Is een van die punten nog vaag, maak het dan duidelijk voordat je functies toevoegt.

De pagina [een iPhone-app maken](https://devoria.fr/nl/expertise/iphone-app-maken) plaatst deze stap in het volledige project. Wil je in de juiste volgorde werken, dan biedt de [iOS Kit](https://devoria.fr/nl/kits/ios) een traject in vier stappen en Starter Code waarin accounts en AI al zitten. Weet je niet meer bij welke stap je verder moet, dan zet de [gratis diagnose](https://devoria.fr/nl/diagnostic) je project weer op volgorde en stuurt je mijn checklist tegen afwijzing door Apple.

## Veelgestelde vragen

### Waar zet je een geheime API-sleutel in een Expo-app?

Op je server, nooit in de app. De Supabase secret- of service_role-sleutel en de geheime sleutel van een AI-aanbieder horen alleen aan de serverkant. De app roept je server aan, die de gebruiker en de limieten controleert voordat hij de aanbieder aanroept. Controleer dat geen van die sleutels in de mobiele bundle staat of in logs die de client kan zien.

### Beschermt een .env-bestand mijn API-sleutel in Expo?

Niet op zichzelf. Een variabele met het voorvoegsel `EXPO_PUBLIC_` is bedoeld voor de code van de app en mag geen serversecret bevatten. Expo legt uit dat deze waarden in het gecompileerde JavaScript terechtkomen en door gebruikers van de app gelezen kunnen worden. Een sleutel naar een `.env`-bestand verplaatsen is dus niet genoeg om hem te beschermen.

### Wat is het verschil tussen een publieke en een geheime API-sleutel?

Een publieke sleutel is bedoeld om in de app mee te leveren: hij identificeert het project, maar vervangt geen rechten op de data. Een geheime sleutel staat geprivilegieerde acties toe en is alleen voor vertrouwde omgevingen. Bij Supabase mag de publishable-sleutel, of de oude anon-sleutel, in de app blijven als de rechten goed zijn ingesteld. De secret- en service_role-sleutels blijven op de server.

### Hoe roep je een AI-API aan vanuit een Expo-app zonder de sleutel bloot te geven?

Laat de aanroep via je server lopen: de app roept de server aan, die de aanbieder aanroept en het antwoord terugstuurt naar de app. De geheime sleutel blijft op de server. Die moet ook de sessie controleren, herhaalde verzoeken beperken en een begrijpelijke fout teruggeven als de aanbieder niet reageert. De client bepaalt niet zelf dat een gebruiker betaalde toegang heeft.

### Hoe controleer je dat elke gebruiker alleen zijn eigen data ziet?

Maak twee testaccounts aan die jij beheert, met in elk een herkenbare notitie. Probeer vanuit account A te lezen, te wijzigen en aan te maken namens account B, en daarna het privébestand van B te openen. Doe de tests ook zonder sessie: elk verzoek moet worden geweigerd of niets onthullen. Noteer het echte resultaat, want "de regels staan aan" is geen testresultaat.

### Hoe vraag je een AI om de sleutels van je app te controleren?

Vraag hem de variabelen van de mobiele code en de server te inventariseren en alleen hun namen te tonen, zonder je geheime waarden te plakken. Vraag hem ook geprivilegieerde aanroepen aan de clientkant te identificeren en een testscript met twee testaccounts voor te stellen. Verbied elke sleutelrotatie of productiewijziging zonder goedkeuring. Zijn antwoord vervangt het uitvoeren van de tests niet.


## Je project

[iOS Kit](https://devoria.fr/nl/kits/ios): Maak je iPhone-app met Claude Code: de Starter Code van mijn apps, skills die zijn werk controleren, en de Apple Review Kit, App Store Screenshots Kit en ASO Kit. 129,99 €.
