n8n External Secrets Tutorial: Connect HashiCorp Vault and AWS Secrets Manager

Introduction

If you run n8n in production, your API keys and tokens multiply fast, and keeping them in n8n’s built-in credential store works until you have multiple instances, a security team with its own vault, or a rotation policy that needs one source of truth. This tutorial shows you how to connect n8n to an external secrets store, starting with a hands-on HashiCorp Vault walkthrough, and how to reference those secrets in credentials without ever pasting the values into n8n.

Quick answer

In n8n, go to Settings > External Secrets, add a vault, pick a provider, and save. Reference secrets in credential fields with {{ $secrets.. }}. Requires an Enterprise license.

Evidence

As of October 2026, n8n’s official documentation lists six supported external secret providers: 1Password (using a self-hosted Connect Server), AWS Secrets Manager, Azure Key Vault, GCP Secrets Manager, HashiCorp Vault, and Infisical. The same page is explicit about the feature’s availability: it is Enterprise-only on both n8n Cloud and self-hosted n8n. Two facts worth internalizing before you start: n8n only supports plaintext values for secrets, not JSON objects, and secrets referenced from a vault only resolve inside credential fields, not in arbitrary expression fields elsewhere in a workflow.

The n8n documentation frames the motivation this way: “This provides an extra layer of security and allows you to manage credentials used across multiple n8n environments in one central place.” That central-place point is the real win. When your staging and production instances both read from the same secrets provider, credential rotation happens once, in the vault, instead of in every instance. For a full overview of running n8n in production, including the admin tasks that surround secrets, see our complete n8n guide.

Prerequisites

  • An n8n instance on an Enterprise plan (n8n Cloud Enterprise, or a self-hosted instance with an Enterprise license). The External Secrets menu does not exist on Community.
  • Docker, if you want to follow the hands-on HashiCorp Vault section (the dev server runs as a container).
  • Basic familiarity with n8n credentials. If you are still setting n8n up, start with our n8n install guide for an Ubuntu VPS.
  • For the AWS section: an IAM identity with secretsmanager:ListSecrets, secretsmanager:BatchGetSecretValue, and secretsmanager:GetSecretValue permissions.

Step 1: Start a local HashiCorp Vault (hands-on lab)

The provider-agnostic n8n steps are identical for all six providers, so this tutorial uses HashiCorp Vault as the concrete example because you can run a real one locally in under a minute. Vault’s dev server is meant for development, never production, which is fine for learning the wiring.

Run the dev server:

docker run -d --name vault-dev -p 8200:8200 \
  -e 'VAULT_DEV_ROOT_TOKEN_ID=devroot' \
  hashicorp/vault server -dev

Wait a few seconds, then export the address and log in with the Vault CLI:

export VAULT_ADDR='http://127.0.0.1:8200'
docker exec vault-dev vault login devroot

You should see Success! You are now authenticated. The dev server enables the KV v2 secrets engine at the secret/ path by default. Now write a test secret the way Vault’s KV v2 documentation describes:

docker exec vault-dev vault kv put secret/n8n/slack bot_token="xoxb-test-token-123"

Verify it reads back:

docker exec vault-dev vault kv get secret/n8n/slack

Expected output includes a bot_token key holding the test value. If you see URL: GET http://127.0.0.1:8200/v1/sys/mounts errors, the server is not fully up yet; wait ten seconds and retry.

Step 2: Connect the vault to n8n

In your n8n instance, go to Settings > External Secrets and click Add secrets vault:

  1. Name: enter a unique name, for example company-vault. This name becomes the first segment of every reference expression, so keep it short and lowercase.
  2. Provider: select HashiCorp Vault.
  3. Vault URL: the address n8n uses to reach Vault, for example http://127.0.0.1:8200 for this lab. In production this is your real Vault cluster URL with TLS.
  4. Authentication Method: select Token and enter the token (devroot in this lab). n8n’s docs describe three supported methods: Token, AppRole, and Userpass. For production, prefer Token auth with a tightly scoped policy or AppRole; the dev root token has god-mode permissions and must never leave your laptop.
  5. If your Vault token cannot read sys/mounts, fill in KV Mount Path and KV Version manually instead of relying on autodiscovery. The minimal policy the docs show for a KV v2 mount at secret/ is:
path "secret/data/*" {
  capabilities = ["read"]
}

path "secret/metadata/*" {
  capabilities = ["read", "list"]
}
  1. Click Save. n8n keeps the store connected until you remove it, and you can then reference its secrets in credentials.

Since n8n 2.10.0 you can connect multiple vaults per provider, so you can attach both a dev and a prod Vault to the same instance if your security policy allows that. If you want isolation between teams, look at project vaults instead: from n8n 2.11.0 an instance admin can share a vault with a single project so only that project’s credentials can reference its secrets.

Step 3: Use the secret in a credential

Secrets from external stores appear inside credentials, not as standalone variables. The official procedure from n8n’s external secret stores documentation:

  1. Create a new credential (for this lab, a Slack OAuth or a generic credential) or open an existing one.
  2. Hover over the field where the secret goes and select Expression.
  3. Enter an expression referencing the secret:
{{ $secrets.company-vault.slack-bot-token }}

The vault name is the one you chose in Step 2, and the secret name is the name of the item as it appears in your vault. Save the credential and run a test node. n8n resolves the value at execution time, so the plaintext never sits in n8n’s database or in exported workflow JSON.

One hard boundary to remember: secrets from a vault only resolve in credential fields. Paste the same expression into a regular Set node parameter and it will not resolve. Plan your workflows around that limit from the start.

Step 4: The AWS Secrets Manager variant

If your team already lives on AWS, the n8n side looks the same but the provider setup differs. In Settings > External Secrets, add a vault with the AWS Secrets Manager provider and choose an authentication method:

  • IAM User: enter the access key ID, secret access key, and region for an IAM user.
  • Auto Detect: n8n uses the AWS SDK default credential provider chain (environment variables, a shared credentials file, or an EC2/ECS/EKS instance role). This avoids long-lived keys, but n8n warns that every Auto Detect vault on the same instance shares one IAM identity, so you cannot scope permissions differently per vault. If you need per-vault scoping, use IAM User with a separate user and an ARN-scoped policy per vault.

Whichever method you pick, the IAM identity needs secretsmanager:ListSecrets, secretsmanager:BatchGetSecretValue, and secretsmanager:GetSecretValue. A restrictive pattern from the docs is to allow listing and batch reads broadly, but scope GetSecretValue to ARNs matching a prefix, for example arn:aws:secretsmanager:us-west-2:123456789000:secret:n8n*, so n8n can only read secrets whose names start with n8n. In your AWS account, name your n8n secrets with that prefix and reference them exactly the same way: {{ $secrets.aws-vault.n8n_slack_token }}.

Step 5: Split secrets by environment the right way

The classic mistake is sharing one n8n instance between dev and prod and hoping secrets sort themselves out. They will not. n8n’s documented pattern is one instance per environment, each connected to a different vault or provider environment. Create dev and prod environments in your secrets provider, generate a token per environment, and wire the dev n8n instance to the dev token and the prod instance to the prod token. The credential expressions stay identical ({{ $secrets.company-vault.slack-bot-token }}), and the values differ automatically.

This is also where n8n’s source control and environments feature pairs naturally with external secrets: workflows move between instances without carrying credential values, because the values live in the vault, not in the workflow. If you run n8n in Docker, our Docker Compose setup guide covers a multi-instance layout you can adapt.

Troubleshooting

Secrets resolve in preview but fail in production

This is the problem n8n’s own docs call out. On versions before n8n 2.13.0 (or when the opt-in toggle is off), only instance owners and admins can resolve secrets at runtime. An owner who edits another user’s credential with a $secrets expression sees it work in preview, but production executions fail. The fix: upgrade to 2.13.0 or newer and turn on Enable external secrets for project roles under Settings > External Secrets, which lets project editors use shared secrets and project admins manage project vaults. On older versions, only use external secrets in credentials owned by an instance owner or admin.

Vault autodiscovery fails with a permissions error

By default n8n reads sys/mounts to discover KV engines. If your Vault token lacks that permission, vault connection silently finds no secrets. Fix it one of two ways: grant the token read access to sys/mounts, or skip autodiscovery entirely by setting KV Mount Path (for example secret/) and KV Version (v1 or v2) in the vault configuration. The token still needs read and list access on the KV path itself.

Your secret holds JSON and n8n refuses it

n8n only supports plaintext values, not JSON objects. If your existing secret is a JSON blob, split it into one secret per value, or store the JSON as a plaintext string in the vault and parse it in a Code node with JSON.parse() at runtime. JSON-in-a-string works because n8n sees it as plaintext; only structured objects are rejected.

Expression shows literally instead of resolving

Two common causes. First, you placed the $secrets expression in a regular node field instead of a credential field; it only resolves in credentials. Second, the vault name in the expression does not match the vault name you entered when adding the store, including case. Double-check the vault name under Settings > External Secrets.

FAQ

See the FAQ list at the top of this page for answers to the questions readers ask most about n8n external secrets: Enterprise availability, where expressions resolve, JSON limitations, dev/prod separation, the provider list, and project role access.

Conclusion

Connecting n8n to an external secrets store moves your API keys out of n8n’s database and into a system built for exactly this job, with rotation, auditing, and per-environment values as the payoff. The concrete skills from this tutorial: standing up a Vault dev server, adding a secrets vault in Settings > External Secrets, referencing secrets with {{ $secrets.vault-name.secret-name }} inside credentials, and splitting dev and prod by connecting each instance to its own vault environment. The one hard requirement is an Enterprise license, so budget for that before you promise your security team a migration. For a broader look at keeping a self-hosted instance healthy and current, read our n8n security patch checklist next.

This article is #93 in the ToolPilot tutorial library.

Frequently asked questions

Is n8n external secrets available on the free Community edition?

No. n8n's official documentation lists external secrets as an Enterprise-only feature, on both n8n Cloud Enterprise and self-hosted Enterprise. Community and Starter plans keep using n8n's built-in encrypted credential store. If you self-host, the cheapest path is a self-hosted Enterprise license; there is no toggle that unlocks this on Community.

Can I use $secrets expressions in any n8n expression field?

No. Secrets stored in an external vault only resolve inside credential fields. If you paste {{ $secrets.my-vault.my-secret }} into a regular node parameter expression, it will not resolve to the value. This is an intentional boundary: credentials are the only place n8n accepts external secret references.

Can I store JSON objects as secrets?

No. n8n only supports plaintext values for external secrets, not JSON objects. The workaround is to store each value as its own secret (for example, separate api_key and api_secret entries) or to store the JSON as a plaintext string and parse it inside a Code node at runtime.

How do I use different secret values for dev and production?

Run one n8n instance per environment and connect each instance to a different vault or provider environment. The official pattern is to create dev and prod environments in your secrets provider, generate a token per environment, and point the dev n8n instance at the dev token and prod at the prod token. A single shared instance cannot give you true secret isolation between environments.

Which providers does n8n support for external secrets?

As of October 2026, the six supported providers are 1Password (via a self-hosted Connect Server), AWS Secrets Manager, Azure Key Vault, GCP Secrets Manager, HashiCorp Vault, and Infisical. HashiCorp Vault Secrets (the HCP cloud product) is explicitly not supported, so do not confuse the two.

Can project members use external secrets, or only instance admins?

From n8n 2.13.0, instance owners and admins can turn on 'Enable external secrets for project roles' under Settings > External Secrets, after which project editors can use shared secrets in credentials and project admins can manage project vaults. On older versions, only instance owners and admins could resolve secrets at runtime.

TP
ToolPilot Team

We install, break, and fix automation tools so you don't have to. Every tutorial on ToolPilot is tested hands-on before publishing.

Keep reading