Skip to content

Proton Pass Plugin

Our Proton Pass plugin enables secure loading of secrets from Proton Pass using declarative instructions within your .env files.

It shells out to the official Proton Pass CLI (pass-cli) to resolve secret references in the format pass://vault/item/field.

  • Secret references via pass:// URIs (pass://vault/item/field)
  • Personal access token login for CI (PROTON_PASS_PERSONAL_ACCESS_TOKEN) — non-interactive, scoped, no full account credentials
  • Non-interactive password login using environment variables (PROTON_PASS_PASSWORD, PROTON_PASS_TOTP, PROTON_PASS_EXTRA_PASSWORD)
  • In-session caching per resolution run
  • Helpful error messages with resolution tips

In a JS/TS project, you may install the @varlock/proton-pass-plugin package as a normal dependency. Otherwise you can just load it directly from your .env.schema file, as long as you add a version specifier.

See the plugins guide for more instructions on installing plugins.

You must have pass-cli installed:

Terminal window
curl -fsSL https://proton.me/download/pass-cli/install.sh | bash

See: Proton Pass CLI overview.

In production/CI you typically want a fully non-interactive login. The plugin supports two authentication methods — a personal access token (recommended) or a username + password.

A personal access token is a scoped, non-interactive credential — it never needs a username, password, or TOTP, which makes it the cleanest option for CI.

Create one with the Proton Pass CLI, then grant it access to the vaults/items it needs:

Terminal window
# Create a token (the full value is only shown once — save it somewhere safe)
pass-cli pat create --name "deploy-bot" --expiration 3m
# PROTON_PASS_PERSONAL_ACCESS_TOKEN=pst_xxxx...xxxx::TOKENKEY
# Grant it access to a vault or item
pass-cli pat access grant ...
.env.schema
# 1. Load the plugin
# @plugin(@varlock/proton-pass-plugin)
#
# 2. Initialize Proton Pass plugin instance
# @initProtonPass(
# id=prod,
# personalAccessToken=$PROTON_PASS_PERSONAL_ACCESS_TOKEN
# )
# ---
# @type=protonPassPersonalAccessToken @sensitive @internal
PROTON_PASS_PERSONAL_ACCESS_TOKEN=

When a personalAccessToken is provided it takes precedence — the plugin runs pass-cli login with the token and ignores username/password/totp/extraPassword.

.env.schema
# @initProtonPass(
# id=prod,
# username=$PROTON_PASS_USERNAME,
# password=$PROTON_PASS_PASSWORD,
# totp=$PROTON_PASS_TOTP,
# extraPassword=$PROTON_PASS_EXTRA_PASSWORD
# )
# ---
# @type=protonPassPassword @sensitive @internal
PROTON_PASS_PASSWORD=
# @type=protonPassTotp @sensitive @internal
PROTON_PASS_TOTP=
# @type=protonPassExtraPassword @sensitive @internal
PROTON_PASS_EXTRA_PASSWORD=

The username is passed as an argument to pass-cli login --interactive <username>. The password/TOTP/extra password are provided to the CLI via environment variables, as supported by Proton Pass CLI login docs: login command.

For local development, especially with multi-process task runners like Turbo, these patterns help reduce repeated prompts:

  • Store Proton Pass credentials in local config items (for example .env.local), wire them into @initProtonPass(...), and encrypt sensitive values using Varlock local encryption.
  • Reuse an existing pass-cli session when possible (pass-cli login once in your terminal before starting your dev tasks).

Use the protonPass() resolver function to fetch a field value from a Proton Pass secret reference.

Secret reference syntax (as documented by Proton Pass CLI): secret references.

.env.schema
# Fetch the `password` field from a secret reference:
DB_PASSWORD=protonPass(pass://Production/Database/password)

When you need multiple plugin instances, use the optional first argument to select the id:

.env.schema
DB_PASSWORD=protonPass(prod, pass://Production/Database/password)

If a secret might not exist, pass allowMissing=true:

.env.schema
OPTIONAL_DB_PASSWORD=protonPass(pass://Production/Database/password, allowMissing=true)

When allowed, missing secrets resolve to an empty string ("").

Initialize a Proton Pass plugin instance for protonPass() resolver.

Key/value args:

  • id (optional): instance identifier for multiple instances
  • personalAccessToken (optional): personal access token (maps to PROTON_PASS_PERSONAL_ACCESS_TOKEN). When set, takes precedence over username/password.
  • username (optional): login username/email passed to pass-cli login --interactive
  • password (optional): pass-cli password (maps to PROTON_PASS_PASSWORD)
  • totp (optional): pass-cli TOTP code (maps to PROTON_PASS_TOTP)
  • extraPassword (optional): pass-cli extra password (maps to PROTON_PASS_EXTRA_PASSWORD)
# @initProtonPass(
# id=prod,
# personalAccessToken=$PROTON_PASS_PERSONAL_ACCESS_TOKEN
# )

Fetch a field value from Proton Pass using a secret reference.

Array args:

  • secretRef (required): pass://vault/item/field
  • instanceId (optional, if 2 args are provided): instance identifier

Key/value args:

  • allowMissing (optional): if true, returns empty string when the secret is missing
# With secret reference (default instance)
DB_PASSWORD=protonPass(pass://Production/Database/password)
# With explicit instance
DB_PASSWORD=protonPass(prod, pass://Production/Database/password)

This resolver uses:

  • pass-cli item view --output json <secretRef> to fetch the requested field
  • pass-cli login only when an auth error occurs, then retries the original command. With a personalAccessToken it runs pass-cli login with PROTON_PASS_PERSONAL_ACCESS_TOKEN set; otherwise it runs pass-cli login --interactive <username> with the password env vars.