4.9.9 Credential Helper Protocol

extra

A credential helper is the authentication hook for Bazel's downloader. Instead of putting tokens in BUILD files, repository rule attributes, or command-line headers, you configure a helper program for the DNS names Bazel downloads from. When a matching download needs credentials, Bazel asks that helper for HTTP headers and keeps the secret-handling logic outside the build graph.1

Credential helpers run inside the downloader path
Bazel checks reusable bytes first; only a cache miss for a scoped host asks the helper for request headers.
Downloader
Receives URL and hash
from repository rule
ctx.download(url = ..., sha256 = ...)

Secrets stay out of rule attributes.

Repository cache
Checks cached bytes
checksum key first
cache hit return bytes
cache miss continue fetch

A cache hit skips helper and network.

cache miss only
Credential helper
Gets domain credentials
matching host scope
helper get
stdin: {"uri": "https://..."}
stdout: {"headers": {...}}

The helper owns token lookup.

Protected host
Returns protected bytes
download then verify
auth HTTP headers
bytes hash verified

Verified bytes can populate the cache.

Repository cache owns reuse. Credential helpers only supply headers. hashes still decide whether bytes are acceptable.

Where It Sits

Repository rules such as http_archive, http_file, and custom rules that call repository_ctx.download() already have a privileged place in the build: they run while external repositories are being materialized, before ordinary analysis actions and before execution sandboxing. That is why earlier items in 4.9 Repository Rules stress hashes, repository cache behavior, and explicit host interactions.

Credential helpers extend that downloader path. They are not a new dependency mechanism, and they do not replace sha256 or integrity. The downloaded bytes still need an expected hash so Bazel can reuse the repository cache safely. The helper only supplies the request headers needed to reach a protected URL.2 With a known hash, Bazel can check the repository cache first and avoid the network entirely when the file is already present.3

Private fetches should still go through repository rules rather than action-time shell downloads. 4.9.2 Archive Downloads & Integrity covers that archive-fetching contract. This article adds the narrower auth piece: once the URL and expected bytes are modeled, the downloader can ask a helper for credentials when needed.4

Scoping Helpers

Configure helpers with --credential_helper. There are three forms: exact DNS match, wildcard match, and a default fallback.5

# .bazelrc
common --credential_helper=downloads.example.com=%workspace%/tools/example-helper
common --credential_helper=*.corp.example.com=%workspace%/tools/corp-helper
common --credential_helper=%workspace%/tools/default-helper

An exact match applies only to that DNS name and takes precedence over other helpers for that host. A wildcard match covers the configured DNS name and its subdomains, while still losing to an exact helper for the same host. A default helper is the fallback when no exact or wildcard scope matches.6

Prefer putting this configuration in the workspace .bazelrc when the whole repository needs the same authenticated endpoints. That makes private fetching part of project invocation policy instead of tribal shell setup.7 It also keeps the helper path reviewable: a credential helper is executable code, so treat changes to it like changes to any other authentication boundary.

The Protocol

The helper is just a program with a small request/response contract. Bazel invokes the helper with the get command, passes the request URI on standard input as JSON, and expects JSON on standard output containing HTTP headers.8

For a GCS-backed dependency, the helper can obtain an access token from gcloud and return an authorization header:

{"headers":{"Authorization":["Bearer ${TOKEN}"]}}

Bazel then attaches those headers to the downloader request.9 If the request fails or returns unexpected content, credentials are invalidated and the helper can be invoked again.10

This shape is intentionally domain-oriented. The helper decides how to talk to the real credential source: cloud CLI, OS keychain, metadata service, short-lived token broker, or vendor SDK. Bazel does not need to learn every provider-specific login flow. It only needs the headers for this request.

The Tweag implementation shows how that small protocol grows without widening Bazel's contract: a short-lived client delegates provider lookup and caching to an in-memory agent, while examples/customized/ replaces the built-in provider and cache behind documented Go interfaces.11 Start from the provider docs and the full consumer example. Use agent, cache, and authentication packages only to diagnose or extend the helper itself.

Why Not Just Use Headers In .bazelrc?

Bazel has several older or narrower authentication paths. The built-in HTTP repository rules expose netrc and auth_patterns, where values from a .netrc file are formatted into an Authorization header for matching hosts.12 Repository-rule authors can also use helper utilities such as get_auth() and use_netrc() to turn .netrc data into an auth dict for repository_ctx.download().13 For non-secret protocol requirements, repository_ctx.download() and download_and_extract() also accept a headers dict directly.14

Those mechanisms are still useful. For example, custom headers let a repository rule request a Docker v2 manifest with an Accept header or issue range requests for stable archive segments.15 But a bearer token is different from an Accept header. The common failure mode is that command-line authentication flags such as --remote_header can show up in CI logs or Build Event Protocol UIs, and redaction is hard to make universal across all header-like flags.16

Credential helpers move the secret retrieval step into a separate binary and keep the configured Bazel flag focused on which helper handles which domain, not on the token value itself.17 That is the same design reason Git and Docker grew credential helpers: the build tool should delegate provider-specific secret lookup instead of growing a built-in authentication matrix.18

Designing A Helper Setup

Start from the endpoint, not from the token. Ask which hosts Bazel will contact during repository fetching and give each sensitive domain the narrowest helper scope that works. storage.googleapis.com is a good concrete example: rules_gcs configures Bazel to use a workspace-local helper only for that host, so private GCS object downloads get credentials without making the helper responsible for every URL Bazel may fetch.19

Keep these design rules in review:

  • Hash every downloaded artifact with sha256 or integrity. The helper authenticates the request, not the content.
  • Scope helpers by DNS name instead of using a default helper unless most downloads really share one credential authority.
  • Do not pass long-lived bearer tokens through .bazelrc, CI command lines, or repository rule attributes.
  • Use direct headers only for protocol negotiation or other non-secret request metadata.
  • Keep helper binaries and scripts under normal code review, and prefer vendor-provided helpers or small wrappers over ad hoc shell that prints tokens.
key takeaway

Credential helpers are the downloader's secret boundary. Repository rules still perform fetching, hashes still protect reproducibility, and the repository cache still provides reuse. The helper's job is narrower: for matching domains, turn a request URI into the HTTP auth headers Bazel needs without embedding credentials in the build graph.

The supply-chain implications continue in 6.7 Build Supply Chain and Releases, where the same separation between declared inputs, authenticated sources, and build provenance becomes part of the broader security model.

Check your understanding · 4 questions

1.What is the credential helper responsible for in Bazel's downloader path?

Select one answer

2.A private artifact URL needs a credential helper, but the file is already in the repository cache and the rule declares sha256 or integrity. What happens when the repository rule runs again?

Select one answer

3.Which statements are true for a well-designed credential helper setup?

Select all that apply

4.True or false: credential helper behavior.

Choose True or False for each sentence

Bazel invokes the helper with a small protocol such as a get command, request URI JSON on stdin, and response JSON on stdout.
A wildcard helper scope such as *.example.com matches a broader set of hosts than an exact host helper and loses to the exact match for that host.
The helper protocol means repository rules no longer need declared URLs or hashes.
A helper returns JSON containing headers that Bazel can attach to the downloader request.
0 of 4 answered

Footnotes

  1. Configuring Bazel's Credential Helper — credential helpers apply to external repositories such as http_archive and http_file, and are configured through --credential_helper.

  2. repository_ctxdownload() and download_and_extract() accept auth / headers but still document sha256 and integrity as the reproducibility guard for remote files.

  3. repository_ctx — with sha256 or integrity, Bazel checks the repository cache before attempting a network download.

  4. Fetching private data with Repo Rules and MODULE Extensions — why genrule plus wget is the wrong model for private external data.

  5. Configuring Bazel's Credential Helper — exact match, wildcard, and default helper forms.

  6. Configuring Bazel's Credential Helper — precedence and scope behavior for exact, wildcard, and default helpers.

  7. Configuring Bazel's Credential Helper — recommendation to put common helper configuration in .bazelrc.

  8. Introducing rules_gcs — helper invocation with get, URI JSON on stdin, and header JSON on stdout.

  9. Introducing rules_gcsAuthorization header JSON returned by the GCS credential helper.

  10. Introducing rules_gcs — retry behavior when credentials fail or content is unexpected.

  11. Tweag credential-helper repository map — protocol orientation, provider setup, a multi-provider consumer workspace, custom provider/cache wiring, focused request fixtures, and symptom routes.

  12. http repository rulesnetrc and auth_patterns on http_archive, http_file, and http_jar.

  13. utils repository rulesget_auth() and use_netrc() return auth dictionaries suitable for ctx.download.

  14. repository_ctxheaders parameter for download() and download_and_extract().

  15. rctx.download custom headers coming to Bazel 7.1 — Docker registry Accept headers and Alpine range-request use cases.

  16. Secure Builds with Credential Helpers — command-line header leaks through CI logs and BEP-backed UIs.

  17. Secure Builds with Credential Helpers — credential helpers act as a secure proxy between the build tool and authentication provider.

  18. Secure Builds with Credential Helpers — Git and Docker precedent, and the motivation for a vendor-independent protocol.

  19. Introducing rules_gcs — GCS-specific .bazelrc helper scope for storage.googleapis.com.