
## Configuring authenticated repositories

\if{text}{
  Note: the configuration of PPM SSO authentication is described in the
  Posit Package Manager SSO authentication section below.
}

<blockquote>
Note: the configuration of PPM SSO authentication is described in the
<a href="#ppm-sso-auth">Posit Package Manager SSO authentication section
below</a>.
</blockquote>

To use authentication you need to include a user name in the repository
URL. You can set the repository URL in the `repos` option with
[base::options()] as usual, or you can use [repo_add()].

```{r}
#| label: setup
#| include: false
# turn off bioc repos, for simplicity
library(pak)
options(pkg.use_bioconductor = FALSE)
options(width = 100)
options(pkg.show_progress = FALSE)
```

For testing purposes pak includes a web app that creates an authenticated
proxy to CRAN. This is how to run the proxy in a subprocess:

```{r}
#| label: proxy-start
#| message: false
repo <- webfakes::new_app_process(pak:::auth_proxy_app())
repo$url()
```

(This needs the webfakes and callr packages.)

Next, we configure the proxy as the main CRAN repository. The default username
of the proxy is `"username"` and the default password is `"token"`. We want to
replace the default CRAN repository with the proxy, so we name it `CRAN`:

```{r}
#| label: repo-add
repo_add(CRAN = repo$url(), username = "username")
repo_get()
```

Note that the output includes a `username` and a `has_password` column.
These are only present if at least one configured repository needs
authentication. `has_password` is `FALSE` here, because pak did not find
the credentials for this repository.

`repo_get()` also displays a message if it cannot find the credentials
for an authenticated repository.

Next we are going to store the credentials in a place where pak can find
them.

## Credential lookup

pak can look up credentials from two sources:
1. The current user's `netrc` file.
2. The system credential store via the keyring package. pak comes with its
   own copy of the keyring package, you don't need to install it
   separately.

### `netrc` files

If the `NETRC` environment variable is set, pak uses its value to
determine the location of the `netrc` file.

Otherwise pak looks for the `netrc` file in current user's home
directory, at `~/.netrc`. On Windows it also looks for `~/_netrc` if the
file starting with a dot does not exist.

If you create a `netrc` file, make sure that is only readable by you.
E.g. on Unix run
```sh
chmod 600 ~/.netrc
```

`netrc` files are simple text files that can store passwords for multiple
hosts. They may contain three types of tokens:

#### `machine <hostname>`

A host name, without the protocol. Subsequent `login` and `password`
tokens belong to this host, until another `machine` token is found, or
the end of file.

#### `login <username>`

User name. It must be preceded by a `machine` token.

#### `password <password>`

Password. It must be preceded by a `machine` and a `login` token.

Whitespace is ignored in `netrc` files. You may include multiple tokens
on the same line, or have one token per line. Here is an example:

```
machine myhost.mydomain.com login myuser password secret
machine myhost2.mydomain.com
login myuser
password secret
login anotheruser
password stillsecret
```

If you need to include whitespace in a password, put the password in double
quotes.

### The credential store

pak uses the keyring package to query the system credential store (or an
alternative keyring credential store) to find credentials for authenticated
repositories. pak comes with a copy of the keyring package, so you don't
need to install it separately.

To store a repository password in the system credential store use the
`repo_auth_key_set()` function. If you want to use a non-default keyring
backend, set the `keyring_backend` option. In this manual we will use
the backend that stores secrets in environment variables. This is an
ephemeral store that is destroyed when the R process terminates.

To continue our example from above:

```{r}
#| label: key-set
options(keyring_backend = "env")
repo_auth_key_set(repo$url(), username = "username", password = "token")
```

Use `repo_auth_key_get()` to check that the key is properly set:

```{r}
#| label: key-get
repo_auth_key_get(repo$url(), username = "username")
```

`repo_get()` now does not show a warning message, and also sets the
`has_password` column to `TRUE`, because pak could find the credentials
for our CRAN proxy:

```{r}
#| label: repo-get
repo_get()
```

### Repo vs. host credentials

pak handles credentials for repositories and hosts. A repository
credential's key is a URL with a non-empty path:
```
https://repo.host.com/repos/repo1
```
A host credential's is an URL with an empty path:
```
https://repo.host.com
```

pak always looks for repository credentials first. If it does not find
any credentials for a repository then it drops the path and looks for
host credentials.

Because `netrc` files only store domain names and not URLs, they can only
contain host credentials.

## Testing

To test that authentication works, use the `repo_status()` function:

```{r}
#| label: repo-status
repo_status()
```

The output of `repo_status()` has extra columns, compared to `repo_get()`,
and it also has a separate row for each platform. If everything works,
then the `has_password` column is `TRUE` for authenticated repositories,
and the `ok` column is `TRUE` if `repo_status()` was able to perform
an (authenticated) HTTP HEAD request to the metadata file of a platform in
a repository.

If you need even more information about repo authentication, e.g. because
`repo_status()` shows some failures, then use the `repo_auth()` function:

```{r}
#| label: repo-auth
repo_auth()
```

The output of `repo_auth()` has the following extra columns:

* `auth_domains`: these are the URLs that pak tries to use as the `service`
  when looking for credentials in the keyring. For our proxy, it tries
  these URLs:
  ```{r}
  #| label: repo-auth-domains
  repo_auth()$auth_domains
  ```
* `auth_domain`: one of `auth_domains`, the URL for which pak found
  credentials in the keyring. If no credentials were found, then this is
  `NA`.
* `auth_source`: a short string that explains where pak found the
  credentials (or `NA` if not credentials were found). For examples
  `netrc` means the user's `netrc` file, and `keyring:macos` means the
  macOS system credential store.
* `auth_error`: `NA` for successful credential search, otherwise a short
  error message on why the search failed. Typically it would fail is the
  credentials are not in the credential store.

## Usage

Once you set up your authenticated repositories, and stored the required
passwords in the system credential store, you can use them like any
other repository. Operations that need authentication will always include
reassuring messages for successful authentications, and warning messages
for failed ones. Function calls that do not perform any HTTP requests,
e.g. because they list cached data, do not display such messages.

```{r}
#| label: meta-update
meta_update()
```

```{r}
#| label: meta-list
meta_list()
```

E.g. here `meta_update()` outputs an authentication message, but
`meta_list()` does not.

<a id="ppm-sso-auth"></a>
## Posit Package Manager SSO authentication

1. To set up PPM SSO authentication, set the `PACKAGEMANAGER_ADDRESS`
environment variable to the URL of your RStudio Package Manager instance.
For example, add this line to your `.Renviron` file:
```
PACKAGEMANAGER_ADDRESS=https://<ppm-url>
```

Alternatively, you can also set it in your shell profile on Unix,
or in the System or User environment variables on Windows.

2. Set `options(repos)` to include a repository from your Package Manager
instance. Include `__token__` as the username in the URL. For example:
```
options(repos = c(
  PPM = "https://__token__@<ppm-url>/<repo-path>",
  getOption("repos")
))
```
You probably want to add this to your `.Rprofile` file, so that it is set
in every R session.

3. Call [repo_get()] to trigger authentication and caching of the token.
You should be prompted to log in via your browser, and the obtained
token will be cached for future use. Call `ppm_sso_status()` to check
the status of your authentication, including the path of the cached
token and its expiration time.

Alternatively, you can call `ppm_sso_login()` directly to trigger
the login process directly.

See also the [Authentication chapter](
  https://docs.posit.co/rspm/admin/authentication/) of the
Posit Package Manager Documentation.
