Skip to content

Aayu8982/aws-secret-manager-client

Repository files navigation

AWS Secrets Manager Client

npm version Build Status Coverage Status License: MIT

A modern, TypeScript-first AWS Secrets Manager client built on AWS SDK v3. This package provides a simplified, promise-based interface for managing secrets with comprehensive error handling, logging, and type safety.

NPM

✨ Features

  • Modern AWS SDK v3: Built on the latest AWS SDK with improved performance and modularity
  • TypeScript First: Full TypeScript support with comprehensive type definitions
  • Async/Await: Promise-based API with async/await support (no more callback hell!)
  • Comprehensive Error Handling: Detailed error handling with custom error types
  • Logging Support: Built-in logging with configurable log levels
  • Health Checks: Built-in health check functionality
  • Type-Safe JSON Parsing: Automatically parse JSON secrets with type safety
  • Retry Logic: Configurable retry policies with exponential backoff
  • Zero Dependencies: Only peer dependency on AWS SDK v3

πŸ“¦ Installation

npm install aws-secret-manager-client @aws-sdk/client-secrets-manager

πŸš€ Quick Start

import { SecretsManagerClient } from 'aws-secret-manager-client';

// Initialize the client
const client = new SecretsManagerClient({
  region: 'us-east-1',
  retryPolicy: {
    maxRetries: 3,
  },
});

// Get a secret
const secret = await client.getSecret('my-app/database/credentials');
console.log(secret.value);

// Get and parse JSON secret with type safety
interface DatabaseConfig {
  host: string;
  port: number;
  username: string;
  password: string;
}

const dbConfig = await client.getSecretJson<DatabaseConfig>('my-app/database/config');
console.log(`Connecting to ${dbConfig.host}:${dbConfig.port}`);

πŸ“š API Reference

Constructor Options

interface SecretsManagerOptions {
  region?: string;
  retryPolicy?: {
    maxRetries?: number;
    retryDelayOptions?: {
      base?: number;
      customBackoff?: (retryCount: number) => number;
    };
  };
  timeout?: number;
  logger?: {
    debug?: (message: string, ...args: any[]) => void;
    info?: (message: string, ...args: any[]) => void;
    warn?: (message: string, ...args: any[]) => void;
    error?: (message: string, ...args: any[]) => void;
  };
}

Methods

getSecret(secretId: string, versionId?: string, versionStage?: string): Promise<SecretValue>

Retrieves a secret from AWS Secrets Manager.

const secret = await client.getSecret('my-secret');
console.log(secret.value);

// Get specific version
const secretVersion = await client.getSecret('my-secret', 'version-id');

// Get specific stage
const secretStage = await client.getSecret('my-secret', undefined, 'AWSPENDING');

getSecretJson<T>(secretId: string, versionId?: string, versionStage?: string): Promise<T>

Retrieves and parses a JSON secret with type safety.

interface ApiKeys {
  stripe: string;
  sendgrid: string;
}

const apiKeys = await client.getSecretJson<ApiKeys>('my-app/api-keys');
console.log(apiKeys.stripe);

createSecret(params: CreateSecretCommandInput): Promise<{arn: string; name: string; versionId: string}>

Creates a new secret in AWS Secrets Manager.

const result = await client.createSecret({
  Name: 'my-app/new-secret',
  Description: 'My new secret',
  SecretString: JSON.stringify({ key: 'value' }),
});
console.log(`Created secret: ${result.name}`);

updateSecret(params: UpdateSecretCommandInput): Promise<{arn: string; name: string; versionId: string}>

Updates an existing secret.

const result = await client.updateSecret({
  SecretId: 'my-app/existing-secret',
  SecretString: JSON.stringify({ key: 'new-value' }),
});
console.log(`Updated secret: ${result.name}`);

deleteSecret(secretId: string, forceDeleteWithoutRecovery?: boolean, recoveryWindowInDays?: number): Promise<{arn: string; name: string; deletionDate: Date}>

Deletes a secret from AWS Secrets Manager.

// Delete with 30-day recovery window (default)
const result = await client.deleteSecret('my-app/old-secret');

// Force delete without recovery
const result = await client.deleteSecret('my-app/old-secret', true);

// Delete with custom recovery window
const result = await client.deleteSecret('my-app/old-secret', false, 7);

rotateSecret(params: RotateSecretCommandInput): Promise<{arn: string; name: string; versionId: string}>

Initiates rotation of a secret.

const result = await client.rotateSecret({
  SecretId: 'my-app/database-password',
  RotationLambdaARN: 'arn:aws:lambda:us-east-1:123456789012:function:rotate-secret',
});

cancelRotateSecret(secretId: string): Promise<{arn: string; name: string; versionId: string}>

Cancels an in-progress secret rotation.

const result = await client.cancelRotateSecret('my-app/database-password');

healthCheck(): Promise<{status: 'healthy' | 'unhealthy'; message: string}>

Performs a health check to verify the client can connect to AWS.

const health = await client.healthCheck();
console.log(`Health status: ${health.status}`);

close(): Promise<void>

Closes the client connection.

await client.close();

πŸ”§ Configuration

Environment Variables

The client supports configuration through environment variables:

AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_SESSION_TOKEN=your-session-token  # For temporary credentials

IAM Permissions

Your IAM user or role needs the following permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:CreateSecret",
        "secretsmanager:UpdateSecret",
        "secretsmanager:DeleteSecret",
        "secretsmanager:RotateSecret",
        "secretsmanager:CancelRotateSecret"
      ],
      "Resource": "*"
    }
  ]
}

πŸ› οΈ Advanced Usage

Custom Logger

import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.Console()
  ]
});

const client = new SecretsManagerClient({
  region: 'us-east-1',
  logger: {
    debug: logger.debug.bind(logger),
    info: logger.info.bind(logger),
    warn: logger.warn.bind(logger),
    error: logger.error.bind(logger),
  },
});

Error Handling

import { SecretsManagerError } from 'aws-secret-manager-client';

try {
  const secret = await client.getSecret('non-existent-secret');
} catch (error) {
  if (error instanceof SecretsManagerError) {
    console.log(`Error code: ${error.code}`);
    console.log(`Status code: ${error.statusCode}`);
    console.log(`Message: ${error.message}`);
    
    switch (error.code) {
      case 'RESOURCE_NOT_FOUND':
        console.log('Secret not found');
        break;
      case 'ACCESS_DENIED':
        console.log('Access denied');
        break;
      default:
        console.log('Unknown error');
    }
  } else {
    console.log('Unexpected error:', error);
  }
}

Express.js Integration

import express from 'express';
import { SecretsManagerClient, SecretsManagerError } from 'aws-secret-manager-client';

const app = express();
const client = new SecretsManagerClient({ region: 'us-east-1' });

app.get('/config', async (req, res) => {
  try {
    const config = await client.getSecretJson('my-app/config');
    res.json({ success: true, data: config });
  } catch (error) {
    if (error instanceof SecretsManagerError) {
      res.status(error.statusCode || 500).json({
        success: false,
        error: {
          code: error.code,
          message: error.message,
        },
      });
    } else {
      res.status(500).json({
        success: false,
        error: { message: 'Internal server error' },
      });
    }
  }
});

// Graceful shutdown
process.on('SIGTERM', async () => {
  await client.close();
  process.exit(0);
});

πŸ§ͺ Testing

Run the test suite:

# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

πŸ“ Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ”— Links

πŸ†• Changelog

v2.0.0

  • BREAKING: Migrated from AWS SDK v2 to v3
  • BREAKING: Removed synchronous methods (all methods are now async)
  • BREAKING: Removed deasync dependency
  • Added TypeScript support
  • Added comprehensive error handling
  • Added logging support
  • Added health check functionality
  • Added retry logic configuration
  • Improved API design with better naming conventions
  • Added comprehensive tests with >80% coverage

v1.x.x

  • Legacy version with AWS SDK v2
  • Synchronous and asynchronous methods
  • Basic functionality

🀝 Support

If you have any questions or need help, please:

  1. Check the documentation
  2. Search existing issues
  3. Create a new issue

Made with ❀️ by Your Name

About

A library for Manage AWS Secret Manager

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published