Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not pre authenticate requests #12496

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
98 changes: 67 additions & 31 deletions docs/html/topics/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

## Basic HTTP authentication

pip supports basic HTTP-based authentication credentials. This is done by
providing the username (and optionally password) in the URL:
pip supports basic HTTP-based authentication credentials. You can provide the
credentials directly in the URLs or using {pypi}`keyring` or a `.netrc` file. When
needed pip will search for credentials in the following order:

1. package URL from requirement (if any)
2. index URLs
3. keyring (if available)
4. `.netrc` file (if present)

## URL credentials support

You can provide the username (and optionally password) directly in the URL:

```
https://username:password@pypi.company.com/simple
Expand Down Expand Up @@ -34,6 +44,15 @@ https://user:he%2F%2Fo@pypi.company.com/simple

[reserved-chars]: https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters


### Securely storing password in keyring

It is recommended to avoid storing password in clear text. For this purpose, you can
use {pypi}`keyring` to store the password securely while still mentioning the username
to use in your URL. pip will then extract the username from the URL and, as it did not
find a password, it will search for a corresponding one in your keyring. See [Keyring
support](#keyring-support) bellow.

## netrc support

pip supports loading credentials from a user's `.netrc` file. If no credentials
Expand Down Expand Up @@ -63,14 +82,45 @@ man pages][netrc-docs].
[netrc-docs]: https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
[netrc-std-lib]: https://docs.python.org/3/library/netrc.html

## Keyring Support
## Keyring support

pip supports loading credentials stored in your keyring using the {pypi}`keyring`
library, which can be enabled by passing `--keyring-provider` with a value of `auto`,
`import`, or `subprocess`. The default value `auto` respects `--no-input` and does not
query keyring at all if the option is used; otherwise it tries the `import`,
`subprocess`, and `disabled` providers (in this order) and uses the first one that
works.

You can explicitly disable keyring support by passing `--keyring-provider=disabled`.

When looking for credentials, pip will first try to find a record in your keyring for
the corresponding URL and if none are found it will try with just the server hostname.

### Storing credentials

In interactive mode, when the keyring is available and the server requires the
user to authenticate, pip will prompt you for the credentials and then save
them in the keyring. In this case the credentials will be saved based on the server
hostname.

You can also manually store your credentials in your keyring, either for an index URL
(note that the URL _must_ end with a `/`):

```
keyring set https://pypi.company.com/dev/simple/ user.name@company.com
```

Or for a server hostname:

pip supports loading credentials stored in your keyring using the
{pypi}`keyring` library, which can be enabled py passing `--keyring-provider`
with a value of `auto`, `disabled`, `import`, or `subprocess`. The default
value `auto` respects `--no-input` and does not query keyring at all if the option
is used; otherwise it tries the `import`, `subprocess`, and `disabled`
providers (in this order) and uses the first one that works.
```
keyring set pypi.company.com user.name@company.com
```

In both cases, `keyring` will prompt you for the password to store.

Note: For server requiring a token instead of a username and password, you can still
store it as the username with an empty password in keyring but due to the limitation of
the `subprocess` provider, this only make sense when using the `import` provider.

### Configuring pip's keyring usage

Expand Down Expand Up @@ -103,6 +153,10 @@ $ export PIP_KEYRING_PROVIDER=disabled
Setting `keyring-provider` to `import` makes pip communicate with `keyring` via
its Python interface.

This is slightly faster than the `subprocess` provider and it makes it possible to use
URLs without any username as it can find it in your keyring. The downside is that you
have to install it in every virtualenv.

```bash
# install keyring from PyPI
$ pip install keyring --index-url https://pypi.org/simple
Expand All @@ -115,9 +169,10 @@ $ pip install your-package --keyring-provider import --index-url https://pypi.co
Setting `keyring-provider` to `subprocess` makes pip look for and use the
`keyring` command found on `PATH`.

For this use case, a username *must* be included in the URL, since it is
required by `keyring`'s command line interface. See the example below or the
basic HTTP authentication section at the top of this page.
The advantage is that you only need to install it once (and it can even be installed
system-wide for all users).
The disadvantage is that, a username *must* be included in the URL, since it is required
by `keyring`'s command line interface. See the example below.

```bash
# Install keyring from PyPI using pipx, which we assume is installed properly
Expand Down Expand Up @@ -163,25 +218,6 @@ from the subprocess in which they run Pip. You won't know whether the keyring
backend is waiting the user input or not in such situations.
```

pip is conservative and does not query keyring at all when `--no-input` is used
because the keyring might require user interaction such as prompting the user
on the console. You can force keyring usage by passing `--force-keyring` or one
of the following:

```bash
# possibly with --user, --global or --site
$ pip config set global.force-keyring true
# or
$ export PIP_FORCE_KEYRING=1
```

```{warning}
Be careful when doing this since it could cause tools such as pipx and Pipenv
to appear to hang. They show their own progress indicator while hiding output
from the subprocess in which they run Pip. You won't know whether the keyring
backend is waiting the user input or not in such situations.
```

Note that `keyring` (the Python package) needs to be installed separately from
pip. This can create a bootstrapping issue if you need the credentials stored in
the keyring to download and install keyring.
Expand Down
2 changes: 2 additions & 0 deletions news/11721.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Wait until the index server tells us that authentication is required before trying
to make sense of the userinfo section of the URLs and potentially query ``keyring``.
2 changes: 2 additions & 0 deletions news/11721.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Removed mention of un-implemented ``--force-keyring`` option.
- Detailed the pros and cons of using the ``import`` and ``subprocess`` keyring providers.
4 changes: 2 additions & 2 deletions src/pip/_internal/cli/cmdoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ class PipOption(Option):
default="auto",
help=(
"Enable the credential lookup via the keyring library if user input is allowed."
" Specify which mechanism to use [disabled, import, subprocess]."
" (default: disabled)"
" Specify which mechanism to use [auto, disabled, import, subprocess]."
" (default: %default)"
),
)

Expand Down