Skip to content

README: document how the API key is stored, and that there is no env-var route #12

Description

@leggetter

Summary

README.md § Credentials explains where to get the API key and that you paste it into
n8n, but says nothing about how it is stored or whether there is a non-UI route.
Both questions come up the moment anyone runs this past a security review, and the answer
differs between n8n Cloud and self-hosted.

The prompt for this was the maintainer asking, mid-review, whether credentials could be set
by environment variable instead of the UI. If that isn't obvious to the person who wrote
the node, it will not be obvious to a user.

The answers, verified against n8n 2.35.7

There is no env-var route to seeding a credential. n8n credentials are database records
encrypted with N8N_ENCRYPTION_KEY; nothing reads a HOOKDECK_API_KEY at startup. Something
has to create the record, and the supported way is the UI.

$env in a credential field is self-hosted only, and off by default since n8n 2.0.
workflow-data-proxy-env-provider.js gates it:

const isEnvAccessBlocked = process.env.N8N_BLOCK_ENV_ACCESS_IN_NODE !== 'false';

Note !== 'false' — blocked unless explicitly opted out. This is a documented n8n 2.0
breaking change ("Block process.env Access in Expressions and Code nodes"), and without the
opt-out the expression throws access to env vars denied.

Our apiKey property does not set noDataExpression, so {{$env.HOOKDECK_API_KEY}} would
work on a self-hosted instance with N8N_BLOCK_ENV_ACCESS_IN_NODE=false. We should not
recommend it
: it weakens a security default globally, for every node in the instance, to
avoid pasting one key once. On Cloud, env vars cannot be set at all, so the option does not
exist.

The credible alternative is n8n External Secrets$secrets.<provider>.<key>, with AWS
Secrets Manager, Azure Key Vault, GCP Secret Manager, Infisical and 1Password. Licence-gated
behind feat:externalSecrets. That is the supported answer to "we don't paste secrets into
UIs", not env vars.

Suggested change

A short subsection under § Credentials — four or five sentences, not an essay:

  • The key is stored encrypted in n8n's database (N8N_ENCRYPTION_KEY), and the field is
    write-only in the UI.
  • There is no environment-variable route to seeding the credential, on Cloud or self-hosted.
  • Enterprise instances can use External Secrets ($secrets.…) instead of pasting the key.
  • {{$env.…}} exists on self-hosted but is blocked by default in n8n 2.x and turning it on
    affects the whole instance — mention only to close the question, and say we don't
    recommend it.

Counter-argument, for the record

This is n8n platform behaviour, not node behaviour, so there is a fair case that it belongs
in n8n's docs rather than ours. The reason I still think it is worth four sentences here:
this package is being submitted for Cloud verification, the Cloud and self-hosted answers
differ, and "how do I supply this secret" is the first question any security review asks
about an integration. Cheap to answer once; repeatedly expensive not to.

There is also a dynamic-credentials.ee module in n8n 2.35 that looks like runtime
credential resolution. I have not investigated it — worth a look before writing the section,
in case it changes the enterprise answer.

Notes

Found while verifying #10. Not changed there — unrelated to that PR, and docs-only.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions