21 : JWT Authentication in FastAPI

 Good Resources:

We are going to authenticate our users using JSON web tokens, In API first approach we mostly see jwt based authentication. In simple words, we supply our email and password once to the API and the API  responds back with a long string/token which is stored by our browsers. The next time when we click on another resource that requires login, The browser will send back the token and the server would be able to identify the user. Just like everything else, It comes with pros and cons. One of the main advantages is, even if the token is stolen, our user's account is not compromised permanently.
In this post we are going to learn to create access token, given an email or a username. We need to create a new file inside core folder. core > security.py and put the following code here.

#core > security.py

from datetime import datetime,timedelta
from typing import Optional
from jose import JWTError, jwt

from core.config import settings


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
    return encoded_jwt
  • We will be receiving a data dictionary with a subject (sub). This sub is ideally an email/username that can uniquely identify each record in the table.
  • data dict. might look like {"sub":"Hello world"}
  • These access tokens will auto-expire in 30 minutes.
  • We make use of secret key and algorithms to encode this data dictionary to get a dedicated access token.

For creating access token we also need a secret_key and name of algorithm to be used. So, lets add these in our core > config.py file
 

import os
from dotenv import load_dotenv

from pathlib import Path
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

class Settings:
    PROJECT_NAME:str = "Job Board"
    PROJECT_VERSION: str = "1.0.0"
    
    ....
    ....
    DATABASE_URL = f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_SERVER}:{POSTGRES_PORT}/{POSTGRES_DB}"

    SECRET_KEY :str = os.getenv("SECRET_KEY")   #new
    ALGORITHM = "HS256"                         #new
    ACCESS_TOKEN_EXPIRE_MINUTES = 30  #in mins  #new

settings = Settings()

Since we are getting the secret key from the environment variable, we need to make this environment variable or we can also add a secret key to our .env file. I am making an extra file .env.template to remind you that you need to have a .env file.

POSTGRES_USER=postgres
POSTGRES_PASSWORD=yourpasswordhere
POSTGRES_SERVER=localhost
POSTGRES_PORT=5432
POSTGRES_DB=yourdbname
SECRET_KEY=supersecretkeyhere!!

We are using python-jose to create access token, we may also use python jwt library but python-jose is updated and kind of superset of python jwt. So, let's stick to python-jose only. Lets add this requirement in requirements.txt file and do a pip install.

fastapi
uvicorn
...
...

#for jwt tokens    #new
python-jose

All done, time to test whether it works or not, Lets test it in cmd/terminal.

Final git commit - create jwt token · nofoobar/JobBoard-Fastapi@26a12c5 (github.com)

Prev: 20 : Deleting … Next: 22 : Authentication …