Skip to content

Armazene e recupere credenciais sensíveis de forma segura usando as APIs nativas de armazenamento de credenciais do sistema operacional.

typescript
import { secrets } from "bun";

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

if (!githubToken) {
  githubToken = prompt("Por favor, insira seu token do GitHub");

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

  console.log("Token do GitHub armazenado");
}

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

console.log(`Logado como ${(await response.json()).login}`);

Visão Geral

Bun.secrets fornece uma API multiplataforma para gerenciar credenciais sensíveis que ferramentas CLI e aplicações de desenvolvimento tipicamente armazenam em arquivos de texto simples como ~/.npmrc, ~/.aws/credentials ou arquivos .env. Ele usa:

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

Todas as operações são assíncronas e não bloqueantes, executando no threadpool do Bun.

NOTE

No futuro, podemos adicionar uma opção `provider` adicional para tornar isso melhor para segredos de implantação em produção, mas hoje esta API é principalmente útil para ferramentas de desenvolvimento local.

API

Bun.secrets.get(options)

Recupera uma credencial armazenada.

typescript
import { secrets } from "bun";

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

// Ou se preferir sem um objeto
const password = await Bun.secrets.get("my-app", "alice@example.com");

Parâmetros:

  • options.service (string, obrigatório) - O serviço ou nome da aplicação
  • options.name (string, obrigatório) - O nome de usuário ou identificador da conta

Retorna:

  • Promise<string | null> - A senha armazenada, ou null se não encontrada

Bun.secrets.set(options, value)

Armazena ou atualiza uma credencial.

typescript
import { secrets } from "bun";

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

Parâmetros:

  • options.service (string, obrigatório) - O serviço ou nome da aplicação
  • options.name (string, obrigatório) - O nome de usuário ou identificador da conta
  • value (string, obrigatório) - A senha ou segredo a armazenar

Notas:

  • Se uma credencial já existir para a combinação service/name dada, ela será substituída
  • O valor armazenado é criptografado pelo sistema operacional

Bun.secrets.delete(options)

Exclui uma credencial armazenada.

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

Parâmetros:

  • options.service (string, obrigatório) - O serviço ou nome da aplicação
  • options.name (string, obrigatório) - O nome de usuário ou identificador da conta

Retorna:

  • Promise<boolean> - true se uma credencial foi excluída, false se não encontrada

Exemplos

Armazenando Credenciais de Ferramenta CLI

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

// Ou se preferir sem um objeto
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");

// Armazena token do registro npm (em vez de ~/.npmrc)
await Bun.secrets.set({
  service: "npm-registry",
  name: "https://registry.npmjs.org",
  value: "npm_xxxxxxxxxxxxxxxxxxxx",
});

// Recupera para chamadas de 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}`,
    },
  });
}

Migrando de Arquivos de Configuração em Texto Simples

javascript
// Em vez de armazenar em ~/.aws/credentials
await Bun.secrets.set({
  service: "aws-cli",
  name: "AWS_SECRET_ACCESS_KEY",
  value: process.env.AWS_SECRET_ACCESS_KEY,
});

// Em vez de arquivos .env com dados sensíveis
await Bun.secrets.set({
  service: "my-app",
  name: "api-key",
  value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
});

// Carrega em tempo de execução
const apiKey =
  (await Bun.secrets.get({
    service: "my-app",
    name: "api-key",
  })) || process.env.API_KEY; // Fallback para CI/produção

Tratamento de Erros

javascript
try {
  await Bun.secrets.set({
    service: "my-app",
    name: "alice",
    value: "password123",
  });
} catch (error) {
  console.error("Falha ao armazenar credencial:", error.message);
}

// Verifica se uma credencial existe
const password = await Bun.secrets.get({
  service: "my-app",
  name: "alice",
});

if (password === null) {
  console.log("Nenhuma credencial encontrada");
}

Atualizando Credenciais

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

// Atualiza para nova senha
await Bun.secrets.set({
  service: "email-server",
  name: "admin@example.com",
  value: "new-password",
});

// A senha antiga é substituída

Comportamento por Plataforma

macOS (Keychain)

  • Credenciais são armazenadas no keychain de login do usuário
  • O keychain pode solicitar permissão de acesso no primeiro uso
  • Credenciais persistem através de reinicializações do sistema
  • Acessível pelo usuário que as armazenou

Linux (libsecret)

  • Requer um daemon de serviço de segredos (GNOME Keyring, KWallet, etc.)
  • Credenciais são armazenadas na coleção padrão
  • Pode solicitar desbloqueio se o keyring estiver bloqueado
  • O serviço de segredos deve estar em execução

Windows (Credential Manager)

  • Credenciais são armazenadas no Windows Credential Manager
  • Visível em Painel de Controle → Credential Manager → Windows Credentials
  • Persiste com flag CRED_PERSIST_ENTERPRISE então é escopo por usuário
  • Criptografado usando Windows Data Protection API

Considerações de Segurança

  1. Criptografia: Credenciais são criptografadas pelo gerenciador de credenciais do sistema operacional
  2. Controle de Acesso: Apenas o usuário que armazenou a credencial pode recuperá-la
  3. Sem Texto Simples: Senhas nunca são armazenadas em texto simples
  4. Segurança de Memória: Bun limpa a memória da senha após o uso
  5. Isolamento de Processo: Credenciais são isoladas por conta de usuário

Limitações

  • Comprimento máximo de senha varia por plataforma (tipicamente 2048-4096 bytes)
  • Nomes de service e name devem ter comprimentos razoáveis (< 256 caracteres)
  • Alguns caracteres especiais podem precisar de escape dependendo da plataforma
  • Requer serviços apropriados do sistema:
    • Linux: Daemon de serviço de segredos deve estar em execução
    • macOS: Keychain Access deve estar disponível
    • Windows: Serviço Credential Manager deve estar habilitado

Comparação com Variáveis de Ambiente

Ao contrário de variáveis de ambiente, Bun.secrets:

  • ✅ Criptografa credenciais em repouso (graças ao sistema operacional)
  • ✅ Evita expor segredos em dumps de memória de processo (memória é zerada após não ser mais necessária)
  • ✅ Sobrevive a reinicializações de aplicação
  • ✅ Pode ser atualizado sem reiniciar a aplicação
  • ✅ Fornece controle de acesso em nível de usuário
  • ❌ Requer serviço de credenciais do SO
  • ❌ Não é muito útil para segredos de implantação (use variáveis de ambiente em produção)

Melhores Práticas

  1. Use nomes de serviço descritivos: Correspondam ao nome da ferramenta ou aplicação Se você estiver construindo uma CLI para uso externo, provavelmente deve usar um UTI (Uniform Type Identifier) para o nome do serviço.

    javascript
    // Bom - corresponde à ferramenta real
    { service: "com.docker.hub", name: "username" }
    { service: "com.vercel.cli", name: "team-name" }
    
    // Evite - muito genérico
    { service: "api", name: "key" }
  2. Apenas credenciais: Não armazene configuração de aplicação nesta API Esta API é lenta, você provavelmente ainda precisa usar um arquivo de configuração para algumas coisas.

  3. Use para ferramentas de desenvolvimento local:

    • ✅ Ferramentas CLI (gh, npm, docker, kubectl)
    • ✅ Servidores de desenvolvimento local
    • ✅ Chaves de API pessoais para teste
    • ❌ Servidores de produção (use gerenciamento de segredos adequado)

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 by www.bunjs.com.cn edit