# Asymmetric Encryption

The [Quick Start](./intro.md) shows you how to use the same
`SIGNING_KEY` that must be shared between all services. This
is called _symmetric encryption_. There's symmetry because
all of the services have the same `SIGNING_KEY`. While
that's not bad, it is not necessarily the best way to sign
the JSON Web Tokens.

Instead, you can use _asymmetric encryption_. It takes just
a little more setup and maintaining some secret files to
use. To use asymmetric encryption, you need to create a
certificate key pair which is composed of a public key and a
private key. It's the private key that you and your team
will need to make sure does not get lost **and that you
don't check it in to your source control**!

```{danger} Private keys are private
You MUST not share your **private key** in your repository
or anywhere someone can get it. Secret management is the
hardest part of having secrets.
```

If your team prefers to use a certificate key pair, the
RS256 or similar encryption algorithm may be used with a
public and private certificate. To do this, see the
following example.

## Generate a Key Pair

Run the following commands in a shell that has **openssl**
installed. If you're on Windows, you can use the **openssl**
in your WSL installation by running the program Ubuntu on
Windows.

```bash
openssl genrsa -out RS256.key 2048
openssl rsa -in RS256.key -pubout -outform PEM -out RS256.key.pub
```

## Configure Authenticator to use Certificates

Now that you have a pair of keys, you need to configure your
instance of `Authenticator` to use them.

1. Create some variables that contains each path to the
   public and private keys
1. Load the public and private keys using Python's built-in
   `open` function
1. When creating your instance of the `Authenticator`:
   1. Pass in the private key as the first argument
   1. Set the `algorithm` argument to `ALGORITHMS.RS256`
      imported from `jose.constants`
   1. Set the `public_key` argument to your private key

```python
# authenticator.py
from jose.constants import ALGORITHMS
import os
    from fastapi import Depends
    from jwtdown_fastapi.authentication import Authenticator
    from queries.accounts import AccountRepo, AccountOut, Account


    class MyAuthenticator(Authenticator):
        async def get_account_data(
            self,
            username: str,
            accounts: AccountRepo,
        ):
            # Use your repo to get the account based on the
            # username (which could be an email)
            return accounts.get(username)

        def get_account_getter(
            self,
            accounts: AccountRepo = Depends(),
        ):
            # Return the accounts. That's it.
            return accounts

        def get_hashed_password(self, account: Account):
            # Return the encrypted password value from your
            # account object
            return account.hashed_password

        def get_account_data_for_cookie(self, account: Account):
            # Return the username and the data for the cookie.
            # You must return TWO values from this method.
            return account.username, AccountOut(**account.dict())

# Create paths to the private and public key files
private_key_path = os.path.join(certs_directory, "RS256.key")
public_key_path = os.path.join(certs_directory, "RS256.key.pub")

# Read the contents of the private and public key files
private_key = open('/path/to/rsa.key', encoding="utf-8")
public_key = open('/path/to/rsa.key.pub', encoding="utf-8")

# Use your private and public keys in the authenticator
authenticator = MyAuthenticator(
    private_key,
    algorithm=ALGORITHMS.RS256,
    public_key=public_key,
)
```
