Skip to content

Archivia e recupera credenziali sensibili in modo sicuro usando le API native di archiviazione credenziali del sistema operativo.

typescript
import { secrets } from "bun";

let githubToken: string | null = await secrets.get({
  service: "my-cli-tool",
  name: "github-token",
});

if (!githubToken) {
  githubToken = prompt("Inserisci il tuo token GitHub");

  await secrets.set({
    service: "my-cli-tool",
    name: "github-token",
    value: githubToken,
  });

  console.log("Token GitHub archiviato");
}

const response = await fetch("https://api.github.com/user", {
  headers: { Authorization: `token ${githubToken}` },
});

console.log(`Accesso effettuato come ${(await response.json()).login}`);

Panoramica

Bun.secrets fornisce un'API cross-platform per gestire credenziali sensibili che gli strumenti CLI e le applicazioni di sviluppo tipicamente archiviano in file di testo in chiaro come ~/.npmrc, ~/.aws/credentials, o file .env. Usa:

  • macOS: Keychain Services
  • Linux: libsecret (GNOME Keyring, KWallet, ecc.)
  • Windows: Windows Credential Manager

Tutte le operazioni sono asincrone e non bloccanti, eseguite sul threadpool di Bun.

NOTE

In futuro, potremmo aggiungere un'opzione `provider` aggiuntiva per renderlo migliore per i segreti di distribuzione in produzione, ma oggi questa API è per lo più utile per gli strumenti di sviluppo locale.

API

Bun.secrets.get(options)

Recupera una credenziale archiviata.

typescript
import { secrets } from "bun";

const password = await Bun.secrets.get({
  service: "my-app",
  name: "alice@example.com",
});
// Restituisce: string | null

// Oppure se preferisci senza un oggetto
const password = await Bun.secrets.get("my-app", "alice@example.com");

Parametri:

  • options.service (string, richiesto) - Il nome del servizio o dell'applicazione
  • options.name (string, richiesto) - Il nome utente o identificativo account

Restituisce:

  • Promise<string | null> - La password archiviata, o null se non trovata

Bun.secrets.set(options, value)

Archivia o aggiorna una credenziale.

typescript
import { secrets } from "bun";

await secrets.set({
  service: "my-app",
  name: "alice@example.com",
  value: "super-secret-password",
});

Parametri:

  • options.service (string, richiesto) - Il nome del servizio o dell'applicazione
  • options.name (string, richiesto) - Il nome utente o identificativo account
  • value (string, richiesto) - La password o segreto da archiviare

Note:

  • Se una credenziale esiste già per la combinazione service/name data, verrà sostituita
  • Il valore archiviato è crittografato dal sistema operativo

Bun.secrets.delete(options)

Elimina una credenziale archiviata.

typescript
const deleted = await Bun.secrets.delete({
  service: "my-app",
  name: "alice@example.com",
  value: "super-secret-password",
});
// Restituisce: boolean

Parametri:

  • options.service (string, richiesto) - Il nome del servizio o dell'applicazione
  • options.name (string, richiesto) - Il nome utente o identificativo account

Restituisce:

  • Promise<boolean> - true se una credenziale è stata eliminata, false se non trovata

Esempi

Archiviazione Credenziali Strumenti CLI

javascript
// Archivia token GitHub CLI (invece di ~/.config/gh/hosts.yml)
await Bun.secrets.set({
  service: "my-app.com",
  name: "github-token",
  value: "ghp_xxxxxxxxxxxxxxxxxxxx",
});

// Oppure se preferisci senza un oggetto
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");

// Archivia token registry npm (invece di ~/.npmrc)
await Bun.secrets.set({
  service: "npm-registry",
  name: "https://registry.npmjs.org",
  value: "npm_xxxxxxxxxxxxxxxxxxxx",
});

// Recupera per chiamate 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}`,
    },
  });
}

Migrazione da File di Configurazione in Testo Chiaro

javascript
// Invece di archiviare in ~/.aws/credentials
await Bun.secrets.set({
  service: "aws-cli",
  name: "AWS_SECRET_ACCESS_KEY",
  value: process.env.AWS_SECRET_ACCESS_KEY,
});

// Invece di file .env con dati sensibili
await Bun.secrets.set({
  service: "my-app",
  name: "api-key",
  value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
});

// Carica a runtime
const apiKey =
  (await Bun.secrets.get({
    service: "my-app",
    name: "api-key",
  })) || process.env.API_KEY; // Fallback per CI/produzione

Gestione Errori

javascript
try {
  await Bun.secrets.set({
    service: "my-app",
    name: "alice",
    value: "password123",
  });
} catch (error) {
  console.error("Archiviazione credenziale fallita:", error.message);
}

// Controlla se una credenziale esiste
const password = await Bun.secrets.get({
  service: "my-app",
  name: "alice",
});

if (password === null) {
  console.log("Nessuna credenziale trovata");
}

Aggiornamento Credenziali

javascript
// Password iniziale
await Bun.secrets.set({
  service: "email-server",
  name: "admin@example.com",
  value: "old-password",
});

// Aggiorna a nuova password
await Bun.secrets.set({
  service: "email-server",
  name: "admin@example.com",
  value: "new-password",
});

// La vecchia password è sostituita

Comportamento per Piattaforma

macOS (Keychain)

  • Le credenziali sono archiviate nel portachiavi di accesso dell'utente
  • Il portachiavi può richiedere il permesso di accesso al primo utilizzo
  • Le credenziali persistono attraverso i riavvii del sistema
  • Accessibile dall'utente che le ha archiviate

Linux (libsecret)

  • Richiede un demone servizio segreti (GNOME Keyring, KWallet, ecc.)
  • Le credenziali sono archiviate nella raccolta predefinita
  • Può richiedere lo sblocco se il portachiavi è bloccato
  • Il servizio segreti deve essere in esecuzione

Windows (Credential Manager)

  • Le credenziali sono archiviate in Windows Credential Manager
  • Visibili in Pannello di controllo → Credential Manager → Credenziali Windows
  • Persistono con il flag CRED_PERSIST_ENTERPRISE quindi sono limitate per utente
  • Crittografate usando Windows Data Protection API

Considerazioni sulla Sicurezza

  1. Crittografia: Le credenziali sono crittografate dal gestore credenziali del sistema operativo
  2. Controllo Accessi: Solo l'utente che ha archiviato la credenziale può recuperarla
  3. Nessun Testo Chiaro: Le password non sono mai archiviate in testo chiaro
  4. Sicurezza Memoria: Bun azzera la memoria della password dopo l'uso
  5. Isolamento Processo: Le credenziali sono isolate per account utente

Limitazioni

  • La lunghezza massima della password varia per piattaforma (tipicamente 2048-4096 byte)
  • I nomi service e name dovrebbero avere lunghezze ragionevoli (< 256 caratteri)
  • Alcuni caratteri speciali potrebbero richiedere escaping a seconda della piattaforma
  • Richiede servizi di sistema appropriati:
    • Linux: Il demone servizio segreti deve essere in esecuzione
    • macOS: Keychain Access deve essere disponibile
    • Windows: Il servizio Credential Manager deve essere abilitato

Confronto con Variabili d'Ambiente

A differenza delle variabili d'ambiente, Bun.secrets:

  • ✅ Crittografa le credenziali a riposo (grazie al sistema operativo)
  • ✅ Evita di esporre segreti nei dump di memoria del processo (la memoria è azzerata dopo che non è più necessaria)
  • ✅ Sopravvive ai riavvii dell'applicazione
  • ✅ Può essere aggiornato senza riavviare l'applicazione
  • ✅ Fornisce controllo accesso a livello di utente
  • ❌ Richiede il servizio credenziali del sistema operativo
  • ❌ Non molto utile per segreti di distribuzione (usa variabili d'ambiente in produzione)

Best Practices

  1. Usa nomi servizio descrittivi: Corrispondi al nome dello strumento o dell'applicazione Se stai costruendo una CLI per uso esterno, probabilmente dovresti usare un UTI (Uniform Type Identifier) per il nome del servizio.

    javascript
    // Buono - corrisponde allo strumento effettivo
    { service: "com.docker.hub", name: "username" }
    { service: "com.vercel.cli", name: "team-name" }
    
    // Da evitare - troppo generico
    { service: "api", name: "key" }
  2. Solo credenziali: Non archiviare configurazione dell'applicazione in questa API Questa API è lenta, probabilmente hai ancora bisogno di usare un file di configurazione per alcune cose.

  3. Usa per strumenti di sviluppo locale:

    • ✅ Strumenti CLI (gh, npm, docker, kubectl)
    • ✅ Server di sviluppo locale
    • ✅ Chiavi API personali per testing
    • ❌ Server di produzione (usa gestione segreti appropriata)

TypeScript

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;
}

Bun a cura di www.bunjs.com.cn