skills/bun-runtime-secrets/SKILL.md
Use Bun's Secrets API to store and retrieve sensitive credentials securely
npx skillsauth add jarle/bun-skills Bun SecretsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use Bun's Secrets API to store and retrieve sensitive credentials securely
Store and retrieve sensitive credentials securely using the operating system's native credential storage APIs.
<Warning>This API is new and experimental. It may change in the future.</Warning>
import { secrets } from "bun";
let githubToken: string | null = await secrets.get({
service: "my-cli-tool",
name: "github-token",
});
if (!githubToken) {
githubToken = prompt("Please enter your GitHub token");
await secrets.set({
service: "my-cli-tool",
name: "github-token",
value: githubToken,
});
console.log("GitHub token stored");
}
const response = await fetch("https://api.github.com/user", {
headers: { Authorization: `token ${githubToken}` },
});
console.log(`Logged in as ${(await response.json()).login}`);
Bun.secrets provides a cross-platform API for managing sensitive credentials that CLI tools and development applications typically store in plaintext files like ~/.npmrc, ~/.aws/credentials, or .env files. It uses:
All operations are asynchronous and non-blocking, running on Bun's threadpool.
<Note> In the future, we may add an additional `provider` option to make this better for production deployment secrets, but today this API is mostly useful for local development tools. </Note>Bun.secrets.get(options)Retrieve a stored credential.
import { secrets } from "bun";
const password = await Bun.secrets.get({
service: "my-app",
name: "[email protected]",
});
// Returns: string | null
// Or if you prefer without an object
const password = await Bun.secrets.get("my-app", "[email protected]");
Parameters:
options.service (string, required) - The service or application nameoptions.name (string, required) - The username or account identifierReturns:
Promise<string | null> - The stored password, or null if not foundBun.secrets.set(options, value)Store or update a credential.
import { secrets } from "bun";
await secrets.set({
service: "my-app",
name: "[email protected]",
value: "super-secret-password",
});
Parameters:
options.service (string, required) - The service or application nameoptions.name (string, required) - The username or account identifiervalue (string, required) - The password or secret to storeNotes:
Bun.secrets.delete(options)Delete a stored credential.
const deleted = await Bun.secrets.delete({
service: "my-app",
name: "[email protected]",
value: "super-secret-password",
});
// Returns: boolean
Parameters:
options.service (string, required) - The service or application nameoptions.name (string, required) - The username or account identifierReturns:
Promise<boolean> - true if a credential was deleted, false if not found// Store GitHub CLI token (instead of ~/.config/gh/hosts.yml)
await Bun.secrets.set({
service: "my-app.com",
name: "github-token",
value: "ghp_xxxxxxxxxxxxxxxxxxxx",
});
// Or if you prefer without an object
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");
// Store npm registry token (instead of ~/.npmrc)
await Bun.secrets.set({
service: "npm-registry",
name: "https://registry.npmjs.org",
value: "npm_xxxxxxxxxxxxxxxxxxxx",
});
// Retrieve for API calls
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}`,
},
});
}
// Instead of storing in ~/.aws/credentials
await Bun.secrets.set({
service: "aws-cli",
name: "AWS_SECRET_ACCESS_KEY",
value: process.env.AWS_SECRET_ACCESS_KEY,
});
// Instead of .env files with sensitive data
await Bun.secrets.set({
service: "my-app",
name: "api-key",
value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
});
// Load at runtime
const apiKey =
(await Bun.secrets.get({
service: "my-app",
name: "api-key",
})) || process.env.API_KEY; // Fallback for CI/production
try {
await Bun.secrets.set({
service: "my-app",
name: "alice",
value: "password123",
});
} catch (error) {
console.error("Failed to store credential:", error.message);
}
// Check if a credential exists
const password = await Bun.secrets.get({
service: "my-app",
name: "alice",
});
if (password === null) {
console.log("No credential found");
}
// Initial password
await Bun.secrets.set({
service: "email-server",
name: "[email protected]",
value: "old-password",
});
// Update to new password
await Bun.secrets.set({
service: "email-server",
name: "[email protected]",
value: "new-password",
});
// The old password is replaced
CRED_PERSIST_ENTERPRISE flag so it's scoped per userUnlike environment variables, Bun.secrets:
Use descriptive service names: Match the tool or application name If you're building a CLI for external use, you probably should use a UTI (Uniform Type Identifier) for the service name.
// Good - matches the actual tool
{ service: "com.docker.hub", name: "username" }
{ service: "com.vercel.cli", name: "team-name" }
// Avoid - too generic
{ service: "api", name: "key" }
Credentials-only: Don't store application configuration in this API This API is slow, you probably still need to use a config file for some things.
Use for local development tools:
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;
}
development
Using TypeScript with Bun, including type definitions and compiler options
development
Learn how to write tests using Bun's Jest-compatible API with support for async tests, timeouts, and various test modifiers
testing
Learn how to use snapshot testing in Bun to save and compare output between test runs
testing
Learn about Bun test's runtime integration, environment variables, timeouts, and error handling