/

Accessing Secrets

Prerequisites

Before accessing secrets, make sure you've installed and initialized the Secrets Manager SDK.

Basic Usage

The ByteHide Secrets Manager offers both asynchronous and synchronous APIs for accessing secrets, giving you flexibility depending on your application needs.

Asynchronous API

The asynchronous API returns Promises and is the recommended approach for most applications:

import { SecretsManager } from "@bytehide/secrets";

// Auto-initializes if environment variables are set
async function getApiCredentials() {
  const apiKey = await SecretsManager.get("API_KEY");
  const apiSecret = await SecretsManager.get("API_SECRET");
  
  return { apiKey, apiSecret };
}

// Example API call with secrets
async function callExternalApi() {
  const { apiKey, apiSecret } = await getApiCredentials();
  
  // Use the secrets
  const response = await fetch('https://api.example.com/data', {
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'X-API-Secret': apiSecret
    }
  });
  
  return response.json();
}

Synchronous API

For scenarios where you need synchronous access, use the getSync method:

import { SecretsManager } from "@bytehide/secrets";

function getDatabaseConfig() {
  // Synchronous retrieval - will block execution
  const host = SecretsManager.getSync("DB_HOST");
  const user = SecretsManager.getSync("DB_USER");
  const pass = SecretsManager.getSync("DB_PASS");
  
  return {
    host,
    user,
    pass
  };
}

// Using the synchronous config
const dbConfig = getDatabaseConfig();
console.log("Database config:", dbConfig);

Creating and Updating Secrets

You can create or update secrets directly from your application:

Asynchronous Set

// Create a new secret
await SecretsManager.set("API_KEY", "sk_test_abc123xyz");

// Update an existing secret with a new value
await SecretsManager.set("DB_PASS", "new-secure-password");

// Confirm the update was successful
console.log("Secret updated:", await SecretsManager.get("DB_PASS"));

Synchronous Set

// Create or update a secret synchronously
SecretsManager.setSync("CONFIG_TIMEOUT", "5000");

// Confirm the update
const timeout = SecretsManager.getSync("CONFIG_TIMEOUT");
console.log("Timeout value:", timeout);

Handling Multiple Environments

The environment is specified during initialization via the BYTEHIDE_SECRETS_ENVIRONMENT variable or in the initialization call. This allows you to automatically use the right secrets for your current environment.

// Development environment
SecretsManager.unsecureInitialize("token", "development");
const devApiKey = await SecretsManager.get("API_KEY");
// Will retrieve the development version of API_KEY

// Production environment
SecretsManager.unsecureInitialize("token", "production");
const prodApiKey = await SecretsManager.get("API_KEY");
// Will retrieve the production version of API_KEY

Error Handling

When a secret doesn't exist or there's an error accessing it, the SDK will throw an exception. Handle this gracefully:

async function getSecretSafely(key) {
  try {
    return await SecretsManager.get(key);
  } catch (error) {
    console.error(`Error retrieving secret ${key}:`, error.message);
    
    // You might want to create the secret or use a default value
    if (error.message.includes("not found")) {
      console.log(`Creating default value for ${key}`);
      await SecretsManager.set(key, "default-value");
      return "default-value";
    }
    
    // Or return a fallback for non-critical secrets
    return null;
  }
}

Best Practices

Configuring Cache

The SDK includes built-in caching to improve performance. By default, caching is enabled with a 5-minute TTL (time-to-live):

// Disable caching for always-fresh values
SecretsManager.configureCache(false);

// Or customize the cache TTL (time-to-live)
// Set cache to 10 minutes (in milliseconds)
SecretsManager.configureCache(true, 10 * 60 * 1000);

// Clear the cache manually when needed
SecretsManager.clearCache();

Security Best Practices

  • Never print or log full secret values
  • Don't store secret values in browser localStorage or sessionStorage
  • Clear secrets from memory when no longer needed
  • Use environment-specific secrets

Common Usage Patterns

Configuration Helper

Create a configuration helper for your application:

// config.js
import { SecretsManager } from "@bytehide/secrets";

export class Config {
  static async getDatabaseConfig() {
    return {
      host: await SecretsManager.get("DB_HOST"),
      user: await SecretsManager.get("DB_USER"),
      password: await SecretsManager.get("DB_PASS"),
      database: await SecretsManager.get("DB_NAME")
    };
  }
  
  static async getApiKeys() {
    return {
      stripe: await SecretsManager.get("STRIPE_KEY"),
      sendgrid: await SecretsManager.get("SENDGRID_KEY"),
      mapbox: await SecretsManager.get("MAPBOX_TOKEN")
    };
  }
  
  static async getFeatureFlags() {
    return {
      betaFeatures: (await SecretsManager.get("ENABLE_BETA")) === "true",
      maintenanceMode: (await SecretsManager.get("MAINTENANCE_MODE")) === "true"
    };
  }
}

Express.js Integration

Integrate with Express.js applications:

// app.js
import express from 'express';
import { SecretsManager } from "@bytehide/secrets";
import { Config } from './config.js';

const app = express();

// Load secrets before starting server
async function startServer() {
  try {
    // Pre-load critical configuration
    const dbConfig = await Config.getDatabaseConfig();
    const apiKeys = await Config.getApiKeys();
    
    // Setup database connection
    await connectToDatabase(dbConfig);
    
    // Store in app context for middleware use
    app.locals.apiKeys = apiKeys;
    
    // Start server
    const port = process.env.PORT || 3000;
    app.listen(port, () => {
      console.log(`Server running on port ${port}`);
    });
  } catch (error) {
    console.error("Failed to start server:", error);
    process.exit(1);
  }
}

startServer();

React Integration

For React applications with server-side rendering:

// Server-side secrets loading
import { SecretsManager } from "@bytehide/secrets";

export async function getServerSideProps() {
  // Get necessary secrets for the page
  const apiKey = await SecretsManager.get("PUBLIC_API_KEY");
  
  return {
    props: {
      apiKey
    }
  };
}

Client-side Secrets

For client-side applications, only include public API keys that are safe to expose to browsers. Never include sensitive secrets in client-side JavaScript bundles.

Next Steps

Previous
Installation