Où ranger ses clés API quand on code avec l'IA
Coller une clé API directement dans le code, c'est le réflexe de tout le monde au début — moi y compris. Ça marche du premier coup, alors on passe à la suite. Sauf que ces clés ont une fâcheuse tendance à voyager : jusque dans le navigateur de tes visiteurs, ou dans l'historique de ton dépôt Git public.
« Dans le code », ce n'est pas une cachette
Quand tu demandes à un assistant IA de brancher une API, il te répond souvent par le chemin le plus court : const apiKey = "sk-..." en haut du fichier. Ce n'est pas une bêtise de sa part — il optimise pour « que ça marche maintenant ». Le problème, c'est ce que devient cette ligne ensuite.
Deux choses qu'on oublie facilement :
- Le code n'est pas secret. S'il tourne dans le navigateur, n'importe qui peut le lire (clic droit, « Inspecter », onglet Sources). Une clé écrite là est aussi publique que le texte de ta page.
- Git n'oublie rien. Tu commites la clé, tu la supprimes au commit suivant… elle reste dans l'historique, accessible à qui clone le dépôt. La retirer « visuellement » ne suffit pas.
La vraie question : client ou serveur ?
C'est la distinction qui change tout, et une fois qu'elle est claire, le reste coule de source.
- Le code côté client est téléchargé et exécuté par le navigateur de chaque visiteur. Tout y est visible.
- Le code côté serveur s'exécute sur une machine que tu contrôles. Ce qui s'y trouve n'est jamais envoyé au visiteur.
Le piège classique des projets front : les préfixes REACT_APP_, VITE_ ou NEXT_PUBLIC_. On croit qu'une variable d'environnement est « cachée » par nature. En réalité, ces préfixes veulent dire exactement l'inverse : « recopie-moi dans le bundle envoyé au navigateur ». La clé finit en clair dans le JavaScript livré.
// ❌ Dans un composant React : la clé part dans le bundle du navigateur
fetch("https://api.openai.com/v1/chat/completions", {
headers: { Authorization: Bearer ${import.meta.env.VITE_OPENAI_KEY} },
});
La solution n'est pas un meilleur nom de variable : c'est de déplacer l'appel. Tu crées une petite route côté serveur qui garde la clé et fait suivre la requête.
// ✅ Côté serveur : la clé reste sur ta machine, jamais exposée
app.post("/api/chat", async (req, res) => {
const r = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: { Authorization: Bearer ${process.env.OPENAI_KEY} },
body: JSON.stringify(req.body),
});
res.json(await r.json());
});
Côté front, tu n'appelles plus l'API directement : tu appelles ton /api/chat. Bonus : tu peux y ajouter une limite de débit ou un contrôle, ce que tu ne pourras jamais faire avec une clé baladée dans le navigateur.
Le duo .env + .gitignore
Pour le développement local, on range les secrets dans un fichier .env, à la racine du projet :
OPENAI_KEY=sk-proj-abc123... DATABASE_URL=postgres://...
Et surtout, on dit à Git de l'ignorer, avec une ligne dans .gitignore :
.env .env.local
Dernier détail qui fait la différence : un fichier .env.example, lui versionné, avec les noms des variables mais sans les valeurs.
OPENAI_KEY= DATABASE_URL=
Comme ça, la prochaine personne — ou ton assistant IA — sait quelles clés sont nécessaires sans jamais voir les vraies. C'est le genre de détail qui sépare un projet bricolé d'un projet propre.
Où vivent les vraies clés en production
Ton .env reste sur ta machine. En production, les vraies valeurs vont dans les variables d'environnement de ton hébergeur. Vercel, Netlify, Railway, Render, Fly… tous ont un écran « Environment Variables » dans leur tableau de bord. Tu y colles OPENAI_KEY et sa valeur, et ton code la lit avec process.env.OPENAI_KEY exactement comme en local.
L'idée à retenir : la clé n'est jamais dans un fichier qui voyage. Elle est injectée par l'environnement, là où le code s'exécute.
Le réflexe d'avant-push
Avant chaque git push, deux commandes valent dix minutes de stress :
git status # qu'est-ce qui part vraiment ? git diff --staged # relis ligne par ligne ce que tu t'apprêtes à commiter
Si tu vois ton .env dans la liste, stop. Et si une clé a déjà été poussée un jour ? Le bon réflexe n'est pas de la cacher : c'est de la régénérer (rotate) chez le fournisseur. Une clé qui a touché un dépôt public est à considérer comme grillée — en révoquer une et en créer une autre prend trente secondes.
GitHub a aussi un filet de sécurité : il scanne les secrets connus et peut bloquer un push ou prévenir le fournisseur, qui désactive parfois la clé tout seul. C'est rassurant, mais ça reste un filet — pas un plan.
En résumé
Rien de tout ça ne te ralentit. C'est trois habitudes : se demander « ce code tourne où ? », garder les secrets dans .env + .gitignore, et jeter un œil avant de pousser. L'IA t'écrit le code en dix secondes ; toi, tu décides où vivent les clés. C'est exactement ça, vibecoder comme un pro.