Repeating username:password in ad-hoc commands, scripts, and runbooks pushes secrets into shell history, process listings, and copied snippets. A .netrc file lets curl read the credential pair from a local secret file instead, which keeps recurring requests shorter and makes credential rotation less disruptive.

When --netrc or --netrc-file is enabled, curl matches the request hostname to a machine entry and uses the corresponding login and password fields for the transfer. The match is based on the host name rather than the URL path, protocol, or port, so the examples below use a masked operations API host and service account to show the lookup flow without exposing a live credential pair.

The file is plain text, so access control matters more than syntax. On Unix-like systems, curl reads $HOME/.netrc by default, while Windows builds check .netrc and _netrc in the home directory; curl does not reject an overly permissive file on its own, so keeping the file private is an operator safeguard rather than a client-enforced rule.

Steps to store cURL credentials in a netrc file:

  1. Create ~/.netrc with one machine block for each protected host that needs stored credentials.
    $ cat <<'EOF' > ~/.netrc
    machine ops-api.example.com
      login svc-health-readonly
      password REDACTED_BASIC_AUTH_PASSWORD
    EOF

    Replace the masked host, account name, and redacted secret placeholder with the real service values; if a default entry is needed, place it after all machine blocks because it matches any host not listed earlier.

  2. Restrict the file so only the account owner can read and write it.
    $ chmod 600 ~/.netrc
    $ ls -l ~/.netrc
    -rw-------  1 user  staff  97 Mar 29 09:18 /home/user/.netrc

    curl does not refuse a group-readable or world-readable netrc file by itself, so permission hardening is a credential-handling requirement rather than an automatic safety check.

  3. Send the request with --netrc so curl loads the matching credential block automatically.
    $ curl --silent --show-error --netrc https://ops-api.example.com/v1/health
    {
      "service": "ops-api",
      "status": "ok",
      "authenticated_as": "svc-health-readonly"
    }

    The masked endpoint represents a Basic-auth protected API; on a real service, the request host must match the machine name in the netrc entry. Use --netrc-file for a dedicated secret file and --netrc-optional when a missing file or entry should not stop the request.

  4. Add --fail and --write-out when the command needs an explicit success signal in scripts or scheduled jobs.
    $ curl --silent --show-error --fail --netrc --write-out "\nHTTP %{http_code}\n" https://ops-api.example.com/v1/health
    {
      "service": "ops-api",
      "status": "ok",
      "authenticated_as": "svc-health-readonly"
    }
    
    HTTP 200

    Pairing the response body with an HTTP 200 trailer makes authentication failures easier to distinguish from DNS, TLS, or application errors in automation logs.

  5. Inspect a verbose trace when the server still returns 401 Unauthorized or an unexpected account.
    $ curl --verbose --silent --netrc https://ops-api.example.com/v1/health
    * Host ops-api.example.com:443 was resolved.
    ##### snipped #####
    * Server auth using Basic with user 'svc-health-readonly'
    > GET /v1/health HTTP/2
    > Host: ops-api.example.com
    > Authorization: Basic ***REDACTED_BASE64_CREDENTIALS***
    > Accept: */*
    ##### snipped #####
    < HTTP/2 200
    < content-type: application/json
    ##### snipped #####
    {
      "service": "ops-api",
      "status": "ok",
      "authenticated_as": "svc-health-readonly"
    }

    Verbose output exposes the encoded Authorization header, so keep traces local and discard or redact them before sharing.

    If --user is still present on the command line, it overrides the netrc credentials and can hide changes made in the file.