
Clés API dans une application mobile : pourquoi ne jamais les embarquer, et que faire à la place
Clé API dans une application mobile : pourquoi ne jamais embarquer une clé secrète OpenAI, Claude ou Stripe, et la petite fonction serveur à utiliser.
Toute clé embarquée dans une application mobile est publique : n’importe qui peut télécharger l’app et lire son contenu, et l’obfuscation ne fait que retarder l’extraction. Les clés secrètes (OpenAI, Claude, Stripe) restent sur un serveur, dans une petite fonction qui vérifie l’utilisateur, applique vos limites et appelle l’API. Les clés faites pour être publiques (configuration Firebase, clé publiable Stripe) peuvent être embarquées si des règles les encadrent.
Si votre application appelle OpenAI, Claude, Stripe ou tout autre service payant avec une clé secrète rangée dans l’app, partez du principe que cette clé est déjà publique. Une application mobile est un fichier que n’importe qui peut télécharger et démonter : la sécurité d’une clé API dans une application mobile tient donc en une règle. Les clés secrètes restent sur un serveur que vous contrôlez, et l’application passe par ce serveur.
Au programme : les clés à garder secrètes, ce qu’il faut construire à la place et que faire après une fuite. Cet article complète mon guide pour lancer une application mobile.
L’IA a changé les projets d’applications, pour moi comme pour tout le monde : ils prennent moins de temps, et de plus en plus d’applications intègrent des fonctions d’IA, comme l’application interne que j’ai créée pour un client débordé de prospects, avec ses intégrations d’IA et de téléphonie. Rien de tout cela ne change l’endroit où doit vivre une clé secrète.
Clé API dans une application mobile : toute clé embarquée est publique
Une application Android est un fichier APK, une application iPhone un fichier IPA : des archives que des outils gratuits et bien documentés savent démonter. La documentation Android le dit sans détour : si le code source de votre application contient des clés API, un attaquant peut décompiler l’application et les retrouver.
Les façons habituelles de cacher une clé n’y changent rien :
- L’obfuscation, ou le découpage de la clé en morceaux, ralentit le lecteur, sans plus : l’application doit reconstituer la clé pour s’en servir, et quiconque fait tourner votre app sur son propre téléphone peut lire les requêtes qu’elle envoie.
- Les fichiers .env et les variables de build ne cachent rien : toute valeur que le code de l’app y lit finit dans l’application. Expo prévient que ses variables
EXPO_PUBLIC_sont visibles en clair dans l’application compilée ; il en va de même pour toute valeur compilée dans une app Flutter, Swift ou Kotlin.
Les fournisseurs sont d’accord. OpenAI demande de ne jamais déployer une clé côté client, dans un navigateur ou une application mobile, et de faire passer les requêtes par votre propre serveur (OpenAI). Anthropic demande de ne jamais inclure la clé directement dans votre code ou vos fichiers de configuration (centre d’aide de Claude). Les bibliothèques JavaScript des deux entreprises refusent même de tourner dans un navigateur sans une option nommée dangerouslyAllowBrowser.
Le coût d’une clé copiée dépend de ce qu’elle ouvre. Une clé d’IA lance des requêtes à vos frais, jusqu’à votre limite, et consomme les quotas de vos vrais utilisateurs. Une clé de base de données ou d’administration cloud ouvre les données de vos utilisateurs.
Clés secrètes et clés conçues pour être publiques
Toutes les clés présentes dans une app ne sont pas des erreurs : certaines sont faites pour être publiques, et la protection se trouve ailleurs.
| Clé | Dans l’app ? | Ce que permet une copie |
|---|---|---|
Clé API OpenAI, Claude (sk-ant-…) ou Mistral AI | Jamais | Des requêtes à vos frais |
Clé secrète Stripe (sk_live_…) ou clé restreinte (rk_live_…) | Jamais | Votre compte Stripe, dans la limite des droits de la clé |
Clé secrète Supabase (sb_secret_…) ou ancienne clé service_role | Jamais | Accès complet à vos données, sécurité RLS contournée |
| Identifiants cloud (compte de service Google Cloud, clé d’accès AWS) | Jamais | Tout ce que leurs droits permettent |
Clé publiable Stripe (pk_live_…) | Oui | Peu de chose : elle est faite pour être publique |
Configuration Firebase (apiKey) | Oui | Ce que vos règles de sécurité autorisent |
Clé publishable Supabase (sb_publishable_…) ou ancienne clé anon | Oui | Ce que la sécurité RLS autorise |
| Clé Google Maps | Oui, restreinte | Des requêtes Maps à vos frais, sauf restriction |
Une clé publique ne vaut que par les règles qui la protègent. Firebase précise que ses clés identifient votre projet sans contrôler l’accès à vos données : ce rôle revient aux règles de sécurité, d’où mon tutoriel pour vérifier vos règles Firebase et Supabase. Deux précautions de plus :
- Restreignez chaque clé publique, quand le fournisseur le permet, à votre application et aux seules API dont elle a besoin. La documentation Android cite Google Maps, dont les clés se limitent au nom de package et à la clé de signature de votre app (sur iOS, à son identifiant de bundle).
- Ne laissez jamais une clé publique appeler une API d’IA payante. Firebase déconseille d’autoriser l’API Gemini Developer sur une clé accessible publiquement : une clé prévue pour une carte ouvrirait votre budget IA.
Que faire à la place : une petite fonction entre votre app et l’API
La solution tient en quelques lignes de code côté serveur, ce qu’on appelle un backend ou un proxy. L’application envoie la demande de l’utilisateur à votre fonction, qui vérifie qui demande, applique vos limites, ajoute la clé et appelle l’API. La clé ne quitte jamais le serveur.
Inutile de louer un serveur : Firebase Cloud Functions, Supabase Edge Functions et Cloudflare Workers n’exécutent le code qu’à l’appel et gardent les clés dans un coffre à secrets, hors de votre code. Voici une fonction Firebase minimale, en JavaScript, qui répond à une question avec Claude (la requête est expliquée dans mon tutoriel sur l’API Claude) :
// functions/index.js — l’app appelle askAssistant, jamais Claude directement
const { onCall, HttpsError } = require("firebase-functions/v2/https");
const { defineSecret } = require("firebase-functions/params");
const claudeKey = defineSecret("ANTHROPIC_API_KEY");
exports.askAssistant = onCall(
{ secrets: [claudeKey], enforceAppCheck: true },
async (request) => {
// 1. Utilisateurs connectés uniquement
if (!request.auth) {
throw new HttpsError("unauthenticated", "Connectez-vous d’abord.");
}
// 2. Vos limites : question courte, modèle fixe, réponse plafonnée
const question = String(request.data?.question ?? "").slice(0, 2000);
if (!question) {
throw new HttpsError("invalid-argument", "La question est vide.");
}
// 3. La clé est ajoutée ici, sur le serveur
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": claudeKey.value(),
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "claude-haiku-5-5",
max_tokens: 1024, // réflexion du modèle comprise
output_config: { effort: "low" }, // moins de réflexion, réponse plus rapide
messages: [{ role: "user", content: question }],
}),
});
if (!response.ok) {
throw new HttpsError("unavailable", "L’assistant est indisponible.");
}
const data = await response.json();
const answer = data.content
.filter((block) => block.type === "text")
.map((block) => block.text)
.join("");
return { answer };
}
);
Enregistrez la clé une fois avec la ligne de commande Firebase, puis déployez (Cloud Functions nécessite le forfait Blaze de Firebase, avec paiement à l’usage) :
firebase functions:secrets:set ANTHROPIC_API_KEY
firebase deploy --only functions
L’app appelle askAssistant via le SDK Firebase, sans jamais voir la clé. Avec OpenAI, seule la requête change, comme le montre mon tutoriel sur l’API ChatGPT (OpenAI).
Pour Gemini, une version toute faite existe : Firebase AI Logic sert de proxy géré, si bien que la clé Gemini reste chez Google, jamais dans votre app.
Rendre la fonction difficile à détourner
Une fois la clé derrière votre fonction, c’est la fonction qu’il faut protéger :
- Utilisateurs connectés uniquement. La vérification de
request.authci-dessus refuse les appels des utilisateurs non connectés. - Des requêtes venues de votre vraie application. App Attest (Apple) et Play Integrity (Google) permettent à votre serveur de vérifier qu’une requête vient d’une copie intacte de votre app, sur un vrai appareil ; Firebase App Check regroupe les deux, et
enforceAppCheck: truerefuse les appels sans jeton valide. Google conseille de faire de Play Integrity un élément de votre stratégie anti-abus, pas votre seul rempart, et Apple prévient que tous les appareils ne prennent pas en charge App Attest : prévoyez le cas où la vérification est impossible. - Une limite quotidienne par utilisateur. Comptez les requêtes de chaque utilisateur dans votre base et refusez au-delà de votre seuil : créer un compte est facile, et cette limite empêche une seule personne de vider votre budget.
- Une limite de dépenses chez le fournisseur. Dans la console Claude, réglez-la sur la page Billing, rubrique Spend limits ; OpenAI propose une limite mensuelle par projet. Choisissez un montant que vous pourriez perdre sans drame : c’est à peu près le maximum qu’une fuite pourra vous coûter en un mois.
Utilisez aussi des clés distinctes pour le développement et la production. Anthropic permet de fixer une date d’expiration à la création d’une clé et conseille de les renouveler à intervalle régulier, par exemple tous les 90 jours.
Gardez les clés hors de votre dépôt de code
Le code de votre fonction vit dans un dépôt ; la clé, non. Gardez-la dans le coffre à secrets de la plateforme et, si vous testez avec un fichier .env local, ajoutez-le au .gitignore avant votre premier commit. Supprimer une clé dans un commit suivant la laisse dans l’historique : une clé poussée est une clé qui a fuité.
GitHub ajoute deux filets de sécurité. La protection des push (push protection) bloque un push qui contient un secret reconnu : elle est active par défaut pour les dépôts publics et, pour les dépôts privés, elle fait partie de l’offre payante GitHub Secret Protection. GitHub repère aussi les clés API Claude dans les dépôts publics, et Anthropic les désactive alors automatiquement en vous prévenant par email. C’est utile, mais il vous faudra de toute façon une nouvelle clé.
Si une clé a déjà fuité : la première heure
Corrigez d’abord, enquêtez ensuite :
- Créez une nouvelle clé et rangez-la dans les secrets de votre serveur, pour que votre fonction continue de tourner.
- Révoquez l’ancienne. Dans la console Claude : page API keys, menu à trois points à côté de la clé, Delete API Key. Chez OpenAI, Stripe ou Supabase, supprimez-la ou remplacez-la dans la section des clés API du tableau de bord. Seule la révocation rend les copies inutilisables ; une mise à jour de l’app, non.
- Vérifiez l’utilisation et la facturation depuis la date possible de l’exposition, et baissez votre limite de dépenses en attendant.
- Publiez une mise à jour qui passe par votre fonction. Les anciennes versions installées gardent la clé révoquée : leurs fonctions d’IA ou de paiement ne marcheront plus tant que l’utilisateur n’aura pas mis l’app à jour. Si votre app prévoit déjà une mise à jour obligatoire, déclenchez-la.
- Demandez-vous si des données personnelles étaient accessibles. La fuite d’une clé de base de données ou d’une clé cloud peut constituer une violation de données personnelles. L’article 33 du RGPD impose alors au responsable du traitement de la notifier à l’autorité de contrôle (la CNIL en France) dans les meilleurs délais et, si possible, 72 heures au plus tard après en avoir pris connaissance, sauf si elle n’est pas susceptible d’engendrer un risque pour les droits et libertés des personnes. Mon guide sur la violation de données dans les 72 heures détaille la marche à suivre. Ceci est une information générale, pas un conseil juridique : si des données personnelles ont pu être exposées, demandez à un avocat ou à votre DPO ce que vous devez déclarer.
Avant de publier : vérifiez l’app compilée, puis la liste
Contrôlez le fichier que vous allez envoyer sur les stores, pas seulement votre code source. Un APK, un AAB ou un IPA est une archive zip : extrayez-en une copie et cherchez-y les premiers caractères de chacune de vos clés secrètes.
unzip -o app-release.apk -d apk-check
grep -r -a -l "sk-ant-" apk-check
Un résultat signale une fuite. L’absence de résultat ne prouve rien pour une clé découpée ou encodée : passez aussi la liste en revue.
- Aucune clé secrète dans le code de l’app, ses variables de build ou ses fichiers de configuration.
- Chaque appel à une API payante passe par votre fonction, qui vérifie l’utilisateur, l’app et une limite quotidienne.
- Une limite de dépenses chez chaque fournisseur d’API.
- Les clés dans le coffre à secrets de la plateforme, aucune dans un dépôt, protection des push activée.
- Des clés distinctes pour le développement et la production, avec une date de renouvellement dans votre agenda.
- Les clés publiques restreintes à votre app et à ses API, et vos règles de base de données testées.
Pour les autres vérifications avant le lancement, suivez ma checklist de sécurité d’une application mobile. Si votre app encaisse des paiements ou stocke des données clients et que personne dans votre équipe n’a jamais écrit de code serveur, faites écrire ou relire la fonction par un développeur : elle est courte, mais c’est elle qui garde les clés.
Questions fréquentes
Peut-on stocker une clé API dans le trousseau iOS ou le Keystore Android ?
Mes utilisateurs peuvent-ils utiliser leur propre clé OpenAI ou Claude ?
Un dépôt GitHub privé suffit-il à protéger une clé API ?
L’épinglage de certificat (certificate pinning) protège-t-il une clé API ?
Comment savoir si quelqu’un utilise ma clé API ?
Joana MehouWebdesigner, spécialiste SEO et cold emailing
Joana Mehou crée des sites web depuis l’âge de onze ans et a fondé MLK Web Studio en 2021, entre Londres et Paris : sites web, SEO, cold emailing et automatisation pour les petites entreprises en France et au Royaume-Uni, avec des conseils honnêtes, y compris quand vous n’avez besoin de personne.
En savoir plus sur le studioDes outils internes et des automatisations construits autour de votre façon de travailler.
Votre application créée avec l’IA laisse-t-elle fuiter des données ? Vérifiez Firebase et Supabase
Sécurité Supabase RLS et règles Firebase : vérifiez si votre app créée avec l’IA laisse n’importe qui lire ses données, puis corrigez avant le lancement.
Sécurité d’une application mobile : la checklist avant lancement (OWASP MASVS simplifié)
Sécurité application mobile : la checklist à suivre avant le lancement, d’après l’OWASP MASVS. Clés API, serveur, jetons, TLS, SDK et version publiée.
API Claude : créer sa clé API et envoyer sa première requête (tutoriel)
Tutoriel API Claude : créer votre clé dans la Claude Console, la protéger, plafonner vos dépenses, envoyer une première requête et comparer les prix.