Authentication, Proxies & Certificates
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the Python Reference bibliography. |
A private index wants credentials, a corporate network wants a proxy, and a TLS-inspecting proxy wants its own certificate
authority trusted. This page shows how pip 26.2.2 handles each. The examples ran on CPython 3.14.6 on 2026-10-22 against a second
birdwatch pypiserver on localhost:8081 that requires HTTP basic authentication for every request, and against PyPI through the
TLS-inspecting egress proxy of the machine that ran them. Credentials are read from the environment variables BIRDWATCH_USER and
BIRDWATCH_PASSWORD; no real credential appears on this page, and none should appear in yours.
Credentials in the index URL
pip accepts HTTP basic authentication credentials in any index URL, https://${BIRDWATCH_USER}:${BIRDWATCH_PASSWORD}@host/simple (with the values from the environment). Many services use a token
as the password, or as the user name with an empty or fixed password; follow the service’s documentation. Characters such as @,
: and / must be percent-encoded (a password he//o becomes he%2F%2Fo).
Without credentials and with --no-input, the server’s 401 makes every page unusable and pip reports the package as missing:
python -m pip download --no-deps --no-input --index-url http://localhost:8081/simple birdtally
Looking in indexes: http://localhost:8081/simple
ERROR: Could not find a version that satisfies the requirement birdtally (from versions: none)
ERROR: No matching distribution found for birdtally
With -vv the reason is visible: Could not fetch URL http://localhost:8081/simple/pip/: 401 Client Error: Unauthorized ….
Without --no-input, pip prompts for a user name and password on a terminal. With credentials from the environment:
python -m pip download --no-deps --index-url "http://${BIRDWATCH_USER}:${BIRDWATCH_PASSWORD}@localhost:8081/simple" birdtally
Looking in indexes: http://birdwatch:****@localhost:8081/simple
Collecting birdtally
Downloading birdtally-0.1.0-py3-none-any.whl (3.7 kB)
Saved ./dl/birdtally-0.1.0-py3-none-any.whl
Successfully downloaded birdtally
pip redacts the password in its own output. It does not redact it in your shell history, CI logs that echo commands, a committed
requirements.txt or a pip.conf. Keep the URL in an environment variable set by your secret store (PIP_INDEX_URL), or use
${VAR} in a requirements file; never commit it.
.netrc
pip also reads ~/.netrc (%HOME%\_netrc on Windows, or the file named by NETRC) through the requests library. With the URL left
without credentials:
machine localhost
login birdwatch
password <the password>
chmod 600 ~/.netrc
python -m pip download --no-deps --index-url http://localhost:8081/simple birdtally
Downloading birdtally-0.1.0-py3-none-any.whl (3.7 kB)
Saved ./dl/birdtally-0.1.0-py3-none-any.whl
Successfully downloaded birdtally
Source: pip: netrc support.
Keyring
pip can ask the keyring library for credentials, so that they live in the operating system’s credential store or come from a
cloud provider’s plugin. --keyring-provider (PIP_KEYRING_PROVIDER, pip 23.1) selects how:
| Value | Behaviour |
|---|---|
|
Try |
|
Never use keyring. |
|
Import the |
|
Run the |
The trap is in the first row: auto does not query keyring at all under --no-input, because a backend might prompt. Tools that
call pip for you (pipx, Pipenv, IDEs) pass --no-input, and CI runs should too, so credentials that "work in my shell" silently
disappear there. Choose import or subprocess explicitly:
pipx install keyring # keyring as an application, outside your project
pipx inject keyring artifacts-keyring # Azure Artifacts backend
pipx inject keyring keyrings.google-artifactregistry-auth # Google Artifact Registry backend
python -m pip config set --user global.keyring-provider subprocess
python -m pip install birdtally --index-url https://oauth2accesstoken@pypi.internal.example/simple/
(Not run here: it needs a real Azure or Google index.) Since pip 26.2 the subprocess provider can also return the user name, and
pip 26.2.1 again allows a keyring installed in a non-activated venv to be used with the import provider while build
dependencies are installed. When pip is called from another tool, forcing a provider can make that tool look
as if it hangs while a backend waits for input that nobody sees.
Proxies
pip uses an HTTP proxy from, in order of precedence:
-
--proxy scheme://[user:passwd@]proxy.server:port(PIP_PROXY, orproxyinpip.conf); -
the standard
http_proxy,https_proxyandno_proxyenvironment variables (and their upper-case forms).
--no-proxy-env (pip 26.2) ignores the environment variables and other non-pip proxy configuration while still honouring an explicit
--proxy; --proxy "" does the same. PIP_USER_AGENT_USER_DATA adds a JSON string to pip’s User-Agent header, which some proxies
and index servers use to route or log requests. A wrong proxy fails with its own error reference:
python -m pip download --no-deps --retries 0 --proxy http://127.0.0.1:9 "tomli-w @ https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl"
Collecting tomli-w @ https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl
error: proxy-connection-failed
× Failed to connect to proxy http://127.0.0.1:9 while fetching https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl
╰─> ('Unable to connect to proxy', NewConnectionError("HTTPSConnection(host='127.0.0.1', port=9): Failed to establish a new connection: [Errno 111] Connection refused"))
hint: This is likely a proxy configuration issue.
Certificates
pip verifies every HTTPS connection. Which certificate authorities it trusts:
-
Since pip 24.2, the system certificate store on Python 3.10 and later, through the
truststorelibrary (before that it was opt-in with--use-feature=truststore). Certificates your operating system or your company’s device management trusts, such as the CA of a TLS-inspecting proxy, therefore work without configuration. -
--use-deprecated=legacy-certsgoes back to the bundledcertifiMozilla bundle only. It exists for compatibility and will disappear. -
--cert <path>(PIP_CERT), orREQUESTS_CA_BUNDLE/CURL_CA_BUNDLE, replaces the store with one PEM bundle. Since 26.2,pip debugreports the configuration level acertsetting comes from.
The machine that ran these examples reaches PyPI through a proxy that re-signs TLS connections with its own CA, which is in the system store but not in certifi. With the variables pointing at a bundle removed, pip’s default works and the legacy mode fails:
python -m pip download --no-cache-dir --no-deps --retries 0 tomli-w # system store: works
python -m pip download --no-cache-dir --no-deps --retries 0 --use-deprecated=legacy-certs \
"tomli-w @ https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl"
Saved ./dl6/tomli_w-1.2.0-py3-none-any.whl
Successfully downloaded tomli-w
…
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1082) - skipping
Collecting tomli-w @ https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl
error: ssl-verification-failed
× Failed to establish a secure connection to files.pythonhosted.org while fetching https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl
╰─> [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1082)
hint: You may need to use --cert or check your proxy/firewall configuration
For index pages the failure is only a Could not fetch URL … - skipping warning followed by (from versions: none); for a file
download it is the ssl-verification-failed diagnostic. The fix is to trust the proxy’s CA (system store, or --cert with a bundle
that contains it), not to disable verification.
-
--client-cert <path>presents a client certificate (a PEM file with the private key and the certificate) for indexes that require mutual TLS. -
--trusted-host <host>marks a host as trusted "even though it does not have valid or any HTTPS". It also lets pip use plain HTTP to that host. It turns off exactly the protection that stops a network attacker from replacing packages; use it only for a host on your own machine or network that you control, and prefer fixing the certificate.
pip and Poetry
| pip | Poetry |
|---|---|
Credentials in the URL, |
|
|
Not documented by Poetry; use the settings above |
|
Poetry uses keyring itself ( |
|
|
|
|
|
The standard |