Asymmetric Encryption
Contents
Asymmetric Encryption#
The Quick Start 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.
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.
Create some variables that contains each path to the public and private keys
Load the public and private keys using Python’s built-in
openfunctionWhen creating your instance of the
Authenticator:Pass in the private key as the first argument
Set the
algorithmargument toALGORITHMS.RS256imported fromjose.constantsSet the
public_keyargument to your private key
# 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,
)