Jacob Paris
← Back to all content

Automatically update your secrets and environment variables from a 1Password vault

Set up .env file

Create a .env file with a variable DEVELOPMENT_ENVS_UPDATED and set it to the current date.

# Update this whenever you make changes to the file
DEVELOPMENT_ENVS_UPDATED=2022-JAN-11

Set up 1Password vault

Follow the instructions on this guide to importing secrets from 1Password to set up a 1Password vault.

When you are done, you will have 4 pieces of information to assign to environment variables.

PASSWORD_TOKEN
PASSWORD_CREDENTIALS
VAULT_ID
ENV_FILE_ID

Create a file sync-env.sh

#!/bin/bash -u
apology () {
echo "💬 Could not update .env file due to missing $1. Check 1Password for the latest .env file"
}
: ${VAULT_ID:?"$(apology VAULT_ID)"}
: ${ENV_FILE_ID:?"$(apology ENV_FILE_ID)"}
: ${PASSWORD_TOKEN:?"$(apology PASSWORD_TOKEN)"}
: ${PASSWORD_CREDENTIALS:?"$(apology PASSWORD_CREDENTIALS)"}
if [ ! "$(command -v docker)" ]; then
echo "💬 Could not update .env file automatically. Check 1Password for the latest variables"
echo "🐳 Docker daemon not installed. Install docker to fetch .env file automatically"
exit 1
fi
docker stop op-connect-api 2>/dev/null && docker rm op-connect-api
docker stop op-connect-sync 2>/dev/null && docker rm op-connect-sync
echo $PASSWORD_CREDENTIALS > "1password-credentials.json"
docker run -d \
--name op-connect-api \
-p 8080:8080 \
-v "$(pwd)/1password-credentials.json:/home/opuser/.op/1password-credentials.json" \
-v "data:/home/opuser/.op/data" \
1password/connect-api:latest
docker run -d \
--name op-connect-sync \
-p 8081:8080 \
-v "$(pwd)/1password-credentials.json:/home/opuser/.op/1password-credentials.json" \
-v "data:/home/opuser/.op/data" \
1password/connect-sync:latest
gp await-port 8080
sleep 5
curl -L "http://0.0.0.0:8080/v1/vaults/$VAULT_ID/items/$ENV_FILE_ID" \
-H "Authorization: Bearer $PASSWORD_TOKEN" \
| jq -r .fields[0].value \
> .env
echo "Stopping container…"
docker stop op-connect-api && docker rm op-connect-api
echo "Stopping container…"
docker stop op-connect-sync && docker rm op-connect-sync
rm "1password-credentials.json"
echo "Updated .env file"

Create a file sync-env.js

const fs = require("fs")
const path = require("path")
/**
* Load environment variables from .env
*
* If they are out of date, or do not exist, download and update them
* If they are newer than this file, update this file
*/
module.exports = function syncEnvFile() {
require("dotenv").config()
/** This variable will update itself when the .env does */
const LATEST_ENVS_DATE = "2022-JAN-11"
if (
process.env.DEVELOPMENT_ENVS_UPDATED !==
LATEST_ENVS_DATE
) {
if (!process.env.DEVELOPMENT_ENVS_UPDATED) {
console.error("The .env file is missing")
} else {
const claimedDate = new Date(
process.env.DEVELOPMENT_ENVS_UPDATED,
)
const latestDate = new Date(LATEST_ENVS_DATE)
if (claimedDate > latestDate) {
const thisFilename = path.basename(__filename)
console.info(
`Updating ${thisFilename} to`,
process.env.DEVELOPMENT_ENVS_UPDATED,
)
console.log("Please commit this change")
const thisFile = fs.readFileSync(
thisFilename,
"utf8",
)
const occurrences =
thisFile.split(LATEST_ENVS_DATE).length - 1
if (occurrences !== 1)
throw new Error("Cannot automatically update")
fs.writeFileSync(
thisFilename,
thisFile.replace(
LATEST_ENVS_DATE,
process.env.DEVELOPMENT_ENVS_UPDATED,
),
"utf-8",
)
return
} else {
console.error(
"The .env file changed on",
LATEST_ENVS_DATE,
)
}
}
const { execSync } = require("child_process")
console.log(
"Downloading latest .env file from 1Password…",
)
try {
execSync("sh sync-env.sh", {
encoding: "utf-8",
})
console.log("The .env file is now up to date")
} catch (error) {
console.error(error.stdout.toString())
}
process.exit(1)
} else {
console.log("The .env file is up to date")
}
}

Usage

As early as possible in your application, add this line of code. In a node server, this is probably the top of your index.js, main.js, or server.js

if (process.env.NODE_ENV !== "production") {
// Update and load .env file
require("./sync-env")()
}

Error cases

Missing 1Password environment variables

Professional headshot

Hi, I'm Jacob

Hey there! I'm a developer, designer, and digital nomad with a background in lean manufacturing.

About once per month, I send an email with new guides, new blog posts, and sneak peeks of what's coming next.

Everyone who subscribes gets access to the source code for this website and every example project for all my tutorials.

Stay up to date with everything I'm working on by entering your email below.

Unsubscribe at any time.