setting-up-a-secure-fastapi-backend-with-jwt-authentication.html

Setting Up a Secure FastAPI Backend with JWT Authentication

In the rapidly evolving world of web development, creating secure and robust applications is more critical than ever. FastAPI, a modern web framework for building APIs with Python 3.6+ based on standard Python type hints, has gained immense popularity for its speed, performance, and ease of use. Implementing JSON Web Tokens (JWT) for authentication adds an essential layer of security to your FastAPI applications. In this article, we will delve into the steps required to set up a secure FastAPI backend with JWT authentication, covering definitions, use cases, and practical coding examples.

What is JWT Authentication?

JWT, or JSON Web Token, is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling verification and trust.

Use Cases for JWT Authentication

  • Stateless Authentication: JWTs are self-contained tokens that carry the necessary information about the user, making it easy to authenticate without maintaining server-side sessions.
  • Cross-Domain Authentication: Useful in microservices architectures where multiple services need to verify a user's identity.
  • Mobile and Web Applications: Ideal for applications requiring secure, scalable authentication mechanisms.

Setting Up FastAPI with JWT Authentication

Step 1: Install Required Packages

First, ensure you have Python installed on your system. Then, create a new project directory and install FastAPI and its dependencies, including uvicorn (ASGI server) and pyjwt (for handling JWTs).

mkdir fastapi-jwt-example
cd fastapi-jwt-example
python -m venv venv
source venv/bin/activate  # On Windows use `venv\Scripts\activate`
pip install fastapi uvicorn pyjwt python-multipart

Step 2: Create the FastAPI Application Structure

Create a file named main.py in your project directory. This file will contain the core of your FastAPI application.

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
import jwt
import datetime

app = FastAPI()

Step 3: Define User Models

Define a Pydantic model for your user data. This model will help validate the data you receive from the client.

class User(BaseModel):
    username: str
    password: str

class UserInDB(User):
    hashed_password: str

Step 4: Set Up JWT Encoding and Decoding

Next, define functions to create and verify JWT tokens. Use a secret key for encoding and decoding the tokens.

SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

def create_access_token(data: dict, expires_delta: datetime.timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.datetime.utcnow() + expires_delta
    else:
        expire = datetime.datetime.utcnow() + datetime.timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def verify_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.PyJWTError:
        return None

Step 5: Implement User Registration and Token Retrieval

Create endpoints for user registration and token retrieval. For simplicity, we’ll store users in memory, but in a real application, you’d use a database.

fake_users_db = {}

@app.post("/register")
async def register(user: User):
    if user.username in fake_users_db:
        raise HTTPException(status_code=400, detail="Username already registered")
    fake_users_db[user.username] = user.password  # In practice, hash the password
    return {"msg": "User created successfully"}

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = fake_users_db.get(form_data.username)
    if not user or user != form_data.password:  # In practice, verify hashed password
        raise HTTPException(status_code=400, detail="Incorrect username or password")
    access_token = create_access_token(data={"sub": form_data.username})
    return {"access_token": access_token, "token_type": "bearer"}

Step 6: Protect Endpoints Using JWT

Now let’s create a protected route that requires a valid token.

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    payload = verify_token(token)
    if payload is None:
        raise HTTPException(status_code=401, detail="Invalid token")
    return {"username": payload.get("sub")}

Step 7: Run the Application

Run your FastAPI application using Uvicorn.

uvicorn main:app --reload

Step 8: Testing the Endpoints

You can test your endpoints using a tool like Postman or CURL.

  1. Register a User:
  2. Send a POST request to /register with { "username": "testuser", "password": "testpassword" }.

  3. Get a Token:

  4. Send a POST request to /token with form data username and password.

  5. Access Protected Route:

  6. Use the token received from the previous step to access /users/me by including it in the Authorization header as Bearer <token>.

Conclusion

Setting up a secure FastAPI backend with JWT authentication is an essential skill for modern web developers. By following the steps outlined in this article, you can create reliable and secure APIs that protect user data and ensure seamless authentication. With FastAPI’s intuitive design and JWT’s robust security features, you can build applications that stand the test of time. Happy coding!

SR
Syed
Rizwan

About the Author

Syed Rizwan is a Machine Learning Engineer with 5 years of experience in AI, IoT, and Industrial Automation.