gcp-secret-credentials-fetcher
gcp-secret-credentials-fetcher
A lightweight, modern Node.js helper utility to easily retrieve, decrypt, and parse credentials and configuration payloads from Google Cloud Secret Manager.
Features
- Automatic JSON Parsing: Automatically parses the secret payload to an object if it's a valid JSON string. Otherwise, returns the raw string.
- Pure JavaScript & Modern Async/Await: Avoids buggy, native C++
deasynccode loops. Ensures maximum compatibility across platforms (Docker, Alpine, Windows, macOS, Linux). - Synchronous Support: Includes a
accessSecretManagerKeySynchelper for CommonJS config files (env.js,config.js) that cannot useawait, using a zero-dependency pure-JS approach viachild_process.spawnSync. - Lazy Initialization: The GCP Client is initialized only when requested, ensuring your app doesn't crash on boot if secrets aren't accessed in that environment.
- Error Fallback Mode: Offers optional legacy-compatible fallback mode, returning a database configuration object with
undefinedproperties instead of throwing an error.
Installation
npm install gcp-secret-credentials-fetcher
Note: Requires Node.js version 18.0.0 or higher.
Google Cloud Credentials Setup
This package uses the official Google Cloud Secret Manager client under the hood, which automatically authenticates using Application Default Credentials (ADC).
1. Local Development (Service Account Key)
- In the Google Cloud Console, create a Service Account and grant it the Secret Manager Secret Accessor role (
roles/secretmanager.secretAccessor). - Download the JSON key file.
- Set the environment variable:
- Windows (PowerShell):
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\path\to\service-account-key.json" - Linux/macOS:
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"
- Windows (PowerShell):
2. Cloud Environment (GCP VM, GKE, Cloud Run, Cloud Functions)
No key file is required. Assign a service account with the Secret Manager Secret Accessor role directly to your Compute instance, GKE pod, or Cloud Run service. The library will authenticate automatically.
Choosing the Right Function
This package exposes two functions for two different situations — both do the same thing (fetch a secret) but in fundamentally different ways:
getSecret / accessSecretManagerKey |
accessSecretManagerKeySync |
|
|---|---|---|
| Returns | Promise<any> |
any (directly) |
Needs await? |
Yes | No |
| Blocks event loop? | No | Yes (briefly, once at startup) |
| Best for | App startup, service handlers | Config files, env.js |
| Solves | General async use | ERR_REQUIRE_ASYNC_MODULE error |
Why does
ERR_REQUIRE_ASYNC_MODULEhappen?
When you useawaitat the top level of a file loaded viarequire(), Node.js treats it as an async ESM module and throws this error.accessSecretManagerKeySyncsolves this by removing the need forawaitentirely — the result is returned directly.
Usage Examples
1. Recommended: Asynchronous Initialization (Async/Await)
For standard Node.js applications, fetch the credentials asynchronously at startup before starting your services:
const getSecret = require('gcp-secret-credentials-fetcher');
async function initializeApp() {
try {
const secretKeyPath = process.env.cassandra_secret_key; // e.g. "projects/123456789/secrets/cassandra-config/versions/latest"
// Fetches and automatically parses the JSON secret payload
const cassandraCredentials = await getSecret(secretKeyPath);
console.log("Secret loaded successfully. Connecting to database...");
console.log("Host:", cassandraCredentials.hostname);
// Start your server/db clients here using the credentials
} catch (error) {
console.error("Failed to load application configurations:", error.message);
process.exit(1);
}
}
initializeApp();
2. Modern Node.js: Top-Level Await (ES Modules)
If your package is configured as an ES module ("type": "module" in your package.json), or you are running in a supported Node.js environment, you can use top-level await:
import getSecret from 'gcp-secret-credentials-fetcher';
const secretKeyPath = process.env.cassandra_secret_key;
const credentials = await getSecret(secretKeyPath);
export default credentials;
3. Legacy Migration / Fallback Mode
If your existing application has a legacy setup that expects an object with empty database fields on error instead of throwing a validation/network exception, pass the { fallbackOnError: true } option:
const getSecret = require('gcp-secret-credentials-fetcher');
async function getDbConfig() {
// If the call fails, this will NOT throw, but instead return:
// { hostname: undefined, ip: undefined, username: undefined, password: undefined, ... }
const credentials = await getSecret(
process.env.cassandra_secret_key,
{ fallbackOnError: true }
);
return credentials;
}
4. Synchronous — For Config Files (env.js / config.js)
Use this when you are loading secrets inside a CommonJS configuration file using require(), where using await at the top level would cause a ERR_REQUIRE_ASYNC_MODULE error:
const { accessSecretManagerKeySync } = require('gcp-secret-credentials-fetcher');
// No async, no await — result is returned directly!
const cassandraConfig = accessSecretManagerKeySync(process.env.cassandra_secret_key);
module.exports = cassandraConfig;
With fallback on error:
const { accessSecretManagerKeySync } = require('gcp-secret-credentials-fetcher');
const cassandraConfig = accessSecretManagerKeySync(
process.env.cassandra_secret_key,
{ fallbackOnError: true } // returns { hostname: undefined, ... } instead of throwing
);
module.exports = cassandraConfig;
API Reference
getSecret(secretKey, [options]) / accessSecretManagerKey(secretKey, [options]) — Async
Returns a Promise resolving to the payload. Must be used with await inside an async function.
Parameters:
secretKey(string, Required): The full resource name of the secret version in Google Cloud, e.g.projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/latestorprojects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/1.options(Object, Optional):fallbackOnError(boolean, Optional): Iftrue, returns a fallback database object with empty (undefined) properties on failure instead of throwing an error. Defaults tofalse.
Returns:
Promise<any>: Resolves to the parsed JSON object if the payload is valid JSON, or the raw UTF-8 string/payload if parsing fails.
accessSecretManagerKeySync(secretKey, [options]) — Synchronous
Blocks execution and returns the secret payload directly — no await required. Internally spawns a short-lived child Node.js process via child_process.spawnSync. Best used in CommonJS configuration files.
Parameters:
secretKey(string, Required): The full resource name of the secret version in Google Cloud, e.g.projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/latest.options(Object, Optional):fallbackOnError(boolean, Optional): Iftrue, returns a fallback database object with empty (undefined) properties on failure instead of throwing an error. Defaults tofalse.
Returns:
any: The parsed JSON object if the payload is valid JSON, or the raw UTF-8 string.
License
MIT 2026