Stockez et récupérez des identifiants sensibles de manière sécurisée en utilisant les API natives de stockage d'identifiants du système d'exploitation.
import { secrets } from "bun";
let githubToken: string | null = await secrets.get({
service: "my-cli-tool",
name: "github-token",
});
if (!githubToken) {
githubToken = prompt("Veuillez entrer votre token GitHub");
await secrets.set({
service: "my-cli-tool",
name: "github-token",
value: githubToken,
});
console.log("Token GitHub stocké");
}
const response = await fetch("https://api.github.com/user", {
headers: { Authorization: `token ${githubToken}` },
});
console.log(`Connecté en tant que ${(await response.json()).login}`);Aperçu
Bun.secrets fournit une API multiplateforme pour gérer des identifiants sensibles que les outils CLI et les applications de développement stockent généralement dans des fichiers en clair comme ~/.npmrc, ~/.aws/credentials, ou des fichiers .env. Il utilise :
- macOS : Keychain Services
- Linux : libsecret (GNOME Keyring, KWallet, etc.)
- Windows : Windows Credential Manager
Toutes les opérations sont asynchrones et non bloquantes, s'exécutant sur le pool de threads de Bun.
NOTE
À l'avenir, nous pourrions ajouter une option `provider` supplémentaire pour rendre cela plus adapté aux secrets de déploiement en production, mais aujourd'hui cette API est surtout utile pour les outils de développement local.API
Bun.secrets.get(options)
Récupère un identifiant stocké.
import { secrets } from "bun";
const password = await Bun.secrets.get({
service: "my-app",
name: "alice@example.com",
});
// Retourne : string | null
// Ou si vous préférez sans objet
const password = await Bun.secrets.get("my-app", "alice@example.com");Paramètres :
options.service(string, requis) - Le nom du service ou de l'applicationoptions.name(string, requis) - Le nom d'utilisateur ou l'identifiant du compte
Retourne :
Promise<string | null>- Le mot de passe stocké, ounulls'il n'est pas trouvé
Bun.secrets.set(options, value)
Stocke ou met à jour un identifiant.
import { secrets } from "bun";
await secrets.set({
service: "my-app",
name: "alice@example.com",
value: "super-secret-password",
});Paramètres :
options.service(string, requis) - Le nom du service ou de l'applicationoptions.name(string, requis) - Le nom d'utilisateur ou l'identifiant du comptevalue(string, requis) - Le mot de passe ou secret à stocker
Notes :
- Si un identifiant existe déjà pour la combinaison service/nom donnée, il sera remplacé
- La valeur stockée est chiffrée par le système d'exploitation
Bun.secrets.delete(options)
Supprime un identifiant stocké.
const deleted = await Bun.secrets.delete({
service: "my-app",
name: "alice@example.com",
value: "super-secret-password",
});
// Retourne : booleanParamètres :
options.service(string, requis) - Le nom du service ou de l'applicationoptions.name(string, requis) - Le nom d'utilisateur ou l'identifiant du compte
Retourne :
Promise<boolean>-truesi un identifiant a été supprimé,falses'il n'a pas été trouvé
Exemples
Stockage d'identifiants d'outils CLI
// Stocker le token GitHub CLI (au lieu de ~/.config/gh/hosts.yml)
await Bun.secrets.set({
service: "my-app.com",
name: "github-token",
value: "ghp_xxxxxxxxxxxxxxxxxxxx",
});
// Ou si vous préférez sans objet
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");
// Stocker le token du registre npm (au lieu de ~/.npmrc)
await Bun.secrets.set({
service: "npm-registry",
name: "https://registry.npmjs.org",
value: "npm_xxxxxxxxxxxxxxxxxxxx",
});
// Récupérer pour les appels API
const token = await Bun.secrets.get({
service: "gh-cli",
name: "github.com",
});
if (token) {
const response = await fetch("https://api.github.com/name", {
headers: {
Authorization: `token ${token}`,
},
});
}Migration depuis des fichiers de configuration en clair
// Au lieu de stocker dans ~/.aws/credentials
await Bun.secrets.set({
service: "aws-cli",
name: "AWS_SECRET_ACCESS_KEY",
value: process.env.AWS_SECRET_ACCESS_KEY,
});
// Au lieu de fichiers .env avec des données sensibles
await Bun.secrets.set({
service: "my-app",
name: "api-key",
value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
});
// Charger au moment de l'exécution
const apiKey =
(await Bun.secrets.get({
service: "my-app",
name: "api-key",
})) || process.env.API_KEY; // Repli pour CI/productionGestion des erreurs
try {
await Bun.secrets.set({
service: "my-app",
name: "alice",
value: "password123",
});
} catch (error) {
console.error("Échec du stockage de l'identifiant :", error.message);
}
// Vérifier si un identifiant existe
const password = await Bun.secrets.get({
service: "my-app",
name: "alice",
});
if (password === null) {
console.log("Aucun identifiant trouvé");
}Mise à jour d'identifiants
// Mot de passe initial
await Bun.secrets.set({
service: "email-server",
name: "admin@example.com",
value: "old-password",
});
// Mettre à jour avec un nouveau mot de passe
await Bun.secrets.set({
service: "email-server",
name: "admin@example.com",
value: "new-password",
});
// L'ancien mot de passe est remplacéComportement par plateforme
macOS (Keychain)
- Les identifiants sont stockés dans le trousseau de connexion de l'utilisateur
- Le trousseau peut demander une autorisation d'accès lors de la première utilisation
- Les identifiants persistent après les redémarrages du système
- Accessibles par l'utilisateur qui les a stockés
Linux (libsecret)
- Nécessite un daemon de service secret (GNOME Keyring, KWallet, etc.)
- Les identifiants sont stockés dans la collection par défaut
- Peut demander un déverrouillage si le trousseau est verrouillé
- Le service secret doit être en cours d'exécution
Windows (Credential Manager)
- Les identifiants sont stockés dans Windows Credential Manager
- Visibles dans Panneau de configuration → Credential Manager → Windows Credentials
- Persistent avec le drapeau
CRED_PERSIST_ENTERPRISEdonc ils sont limités par utilisateur - Chiffrés en utilisant Windows Data Protection API
Considérations de sécurité
- Chiffrement : Les identifiants sont chiffrés par le gestionnaire d'identifiants du système d'exploitation
- Contrôle d'accès : Seul l'utilisateur qui a stocké l'identifiant peut le récupérer
- Pas de texte clair : Les mots de passe ne sont jamais stockés en texte clair
- Sécurité mémoire : Bun efface la mémoire des mots de passe après utilisation
- Isolation des processus : Les identifiants sont isolés par compte utilisateur
Limitations
- La longueur maximale du mot de passe varie selon la plateforme (généralement 2048-4096 octets)
- Les noms de service et d'utilisateur doivent avoir des longueurs raisonnables (< 256 caractères)
- Certains caractères spéciaux peuvent nécessiter un échappement selon la plateforme
- Nécessite des services système appropriés :
- Linux : Le daemon de service secret doit être en cours d'exécution
- macOS : Keychain Access doit être disponible
- Windows : Le service Credential Manager doit être activé
Comparaison avec les variables d'environnement
Contrairement aux variables d'environnement, Bun.secrets :
- ✅ Chiffre les identifiants au repos (grâce au système d'exploitation)
- ✅ Évite d'exposer les secrets dans les vidages de mémoire de processus (la mémoire est effacée après qu'elle n'est plus nécessaire)
- ✅ Survit aux redémarrages d'applications
- ✅ Peut être mis à jour sans redémarrer l'application
- ✅ Fournit un contrôle d'accès au niveau de l'utilisateur
- ❌ Nécessite un service d'identifiants du système d'exploitation
- ❌ Pas très utile pour les secrets de déploiement (utilisez des variables d'environnement en production)
Bonnes pratiques
Utilisez des noms de service descriptifs : Faites correspondre le nom de l'outil ou de l'application Si vous construisez un CLI pour une utilisation externe, vous devriez probablement utiliser un UTI (Uniform Type Identifier) pour le nom du service.
javascript// Bon - correspond à l'outil réel { service: "com.docker.hub", name: "username" } { service: "com.vercel.cli", name: "team-name" } // À éviter - trop générique { service: "api", name: "key" }Uniquement les identifiants : Ne stockez pas la configuration de l'application dans cette API Cette API est lente, vous aurez probablement toujours besoin d'utiliser un fichier de configuration pour certaines choses.
Utilisez pour les outils de développement local :
- ✅ Outils CLI (gh, npm, docker, kubectl)
- ✅ Serveurs de développement local
- ✅ Clés API personnelles pour les tests
- ❌ Serveurs de production (utilisez une gestion appropriée des secrets)
TypeScript
namespace Bun {
interface SecretsOptions {
service: string;
name: string;
}
interface Secrets {
get(options: SecretsOptions): Promise<string | null>;
set(options: SecretsOptions, value: string): Promise<void>;
delete(options: SecretsOptions): Promise<boolean>;
}
const secrets: Secrets;
}