BytesafeDependency Firewall

npm

Configure npm, yarn, pnpm, and Bun to install through your firewall. Registry setup, authentication, CI, publishing, and troubleshooting.

An npm firewall implements the npm registry protocol. Anything that speaks it can install through the firewall: npm, yarn, pnpm, and Bun. It covers the operations that move packages, which are listed in Client operations.

The examples use <namespace-id> and <firewall-id> placeholders. Replace them with IDs, not with namespace or firewall names. The firewall's Setup tab shows a ready-to-copy npm snippet with both values already filled in. This page also covers yarn, pnpm, and Bun, whose configuration is not generated in the dashboard.

Registry endpoint

https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/

The namespace ID and firewall ID are part of the URL, so one machine can use different firewalls per project.

Configure the project

Commit a .npmrc at the project root:

.npmrc
registry=https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/
//eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/:_authToken=${BYTESAFE_TOKEN}

npm 6 and earlier need always-auth=true as well, see always-auth.

Yarn 1 (Classic) reads the same .npmrc as npm, and needs one extra line:

.npmrc
registry=https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/
//eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/:_authToken=${BYTESAFE_TOKEN}
always-auth=true

Without always-auth, Yarn Classic does not send credentials on reads, and every install fails with a 401. See always-auth.

Yarn Berry (2+) uses its own config and needs no equivalent:

.yarnrc.yml
npmRegistryServer: "https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/"
npmAuthToken: "${BYTESAFE_TOKEN}"

pnpm reads the same .npmrc as npm:

.npmrc
registry=https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/
//eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/:_authToken=${BYTESAFE_TOKEN}

Bun reads .npmrc, or its own config:

bunfig.toml
[install]
registry = { url = "https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/npm/<firewall-id>/", token = "$BYTESAFE_TOKEN" }

Each developer exports a personal access token:

export BYTESAFE_TOKEN=<your token>

Committing the registry config, with the token read from an environment variable, gives every clone of the repository the firewall by default and keeps credentials out of git.

always-auth

The firewall requires an access token on every request, metadata reads included, and never sends an authentication challenge. A client that waits to be challenged before presenting credentials gets a 401 instead.

Modern npm does not wait. It matches the registry-scoped :_authToken line against the request URL and sends the token every time, so the .npmrc above needs nothing further. always-auth was npm 6's way of forcing the same behavior; npm 7 and later dropped the setting, and current versions warn that it is an unknown config.

Add always-auth=true only for a client that still needs it:

  • Yarn Classic (1.x). Required. Without it, reads are unauthenticated and fail.
  • npm 6 and earlier. Required, for the same reason.

A project shared by Yarn Classic and a current npm keeps the line and lives with npm's unknown-config warning. npm ignores the setting, Yarn Classic depends on it, and the warning has no effect on the install.

Verify

npm install lodash
yarn add lodash
pnpm add lodash
bun add lodash

A successful install confirms the firewall is serving the package, and every request through that registry is evaluated against your rules.

Do not expect a log entry from this. A request is logged only when it matches a rule with log: true or a logging exception, so an install that breaks no rule leaves no trace. An empty log is not evidence that the client bypassed the firewall. To see the requests while verifying setup, add a log-only rule that matches all packages. See What is logged when. For a record of what was actually served, see See what was actually downloaded.

CI

Use a Service Access Token (SAT) instead of a PAT. Set it as a secret in your CI system and export it as BYTESAFE_TOKEN before install steps. The committed registry config does the rest.

To correlate all requests from one pipeline run, append an interaction ID to the token:

export BYTESAFE_TOKEN="${BYTESAFE_TOKEN}::${CI_PIPELINE_ID}"

The ID shows up on every log entry from that run.

npm audit

npm audit works through the firewall, with one thing to know: audit requests are answered by npmjs.org. The firewall needs network access to that host for them to succeed, and the request carries the names and versions in your dependency tree there. If you block public registry egress, exempt npmjs.org or expect npm audit to stop working.

Audit requests are also not evaluated against your rules. They ask about known vulnerabilities; they do not fetch packages. To enforce policy on vulnerabilities, use a vulnerabilities rule, which runs on the download path and uses the firewall's own advisory data.

Publishing

A firewall can also receive npm publish. First set a publish target: the upstream that should receive published packages. Then publish as usual with the firewall as the registry. Upload rules run against the publish before it is forwarded.

Without a publish target the firewall is install-only and rejects publishes. That is a deliberate setting, not a limitation: leave it unset on firewalls that should only pull packages in.

What a blocked install looks like

Rules on the versions phase filter versions out of the metadata npm sees. Dist-tags pointing at a filtered version are removed. The effect depends on how the dependency is declared:

  • A range like ^4.0.0 resolves to the newest version that passed the rules. The install succeeds, possibly with an older version than the public latest.
  • An exact pin to a filtered version fails with npm's No matching version found error (ETARGET).
  • A named tag spec like some-package@canary fails the same way when the tag points at a filtered version, because the tag is removed from the metadata. The default tag is the exception: npm install some-package (implicitly @latest) falls back and resolves to the newest version that passed the rules, like a range.

Rules on the download phase block the tarball fetch instead. The blocked version is often a transitive dependency that a range resolved to, not the package on the command line. npm fails with a 404 from the firewall and a message like:

lodash@4.17.20 is blocked. Check firewall log entries for request <request-id> for details

Take the request ID to the logs to see which rule fired. See Investigate a blocked install.

Troubleshooting

BYTESAFE_TOKEN is unset, expired, or revoked. Confirm the variable is set in the shell that runs the install, and that the token is still listed and unexpired in the dashboard.

Most likely a versions rule filtered it. Check the firewall logs before assuming an upstream problem.

Expected. The firewall implements the operations that move packages: resolve, download, publish, and audit. Identity and access are managed in the web interface rather than through a package manager, so whoami, login, logout, and token commands are not part of the endpoint. npm search is not either, because searching is not a step in resolving or fetching a package.

To check which identity a token carries, use bsfw whoami. For the full picture, see Client operations.

No log entry does not by itself mean the client bypassed the firewall. Approved packages that match no logging rule pass through without an entry. First test with a log-only rule matching the package or all packages. If that rule still does not produce an entry, check for overriding config in ~/.npmrc or a NPM_CONFIG_REGISTRY environment variable, and confirm lockfile resolved URLs point at the firewall, not registry.npmjs.org.

If you route only certain scopes through the firewall (@acme:registry=...), everything outside the scope still goes to the public registry unchecked. Route the whole registry through the firewall unless you have a reason not to.

On this page