creating-a-secure-api-using-fastapi-with-jwt-authentication.html

Creating a Secure API Using FastAPI with JWT Authentication

In today's digital landscape, securing APIs is paramount. Whether you're building a web application, a mobile app, or an IoT solution, ensuring that your API is secure protects your data and your users. FastAPI, an increasingly popular web framework for building APIs in Python, offers built-in support for various authentication methods, including JSON Web Tokens (JWT). In this article, we will explore how to create a secure API using FastAPI with JWT authentication, providing you with a step-by-step guide, code examples, and actionable insights.

Understanding JWT Authentication

What is JWT?

JSON Web Tokens (JWT) are an open standard for securely transmitting information between parties as a JSON object. These tokens can be verified and trusted because they are digitally signed. JWTs are commonly used for authentication and information exchange in web applications.

Why Use JWT?

  • Statelessness: JWTs are self-contained and do not require session storage on the server.
  • Compact: They are URL-safe and can be easily transmitted in HTTP headers.
  • Versatile: JWTs can carry different types of information, making them suitable for various use cases like user authentication and authorization.

Setting Up FastAPI

Before we dive into JWT authentication, let’s set up a basic FastAPI application. If you haven't already, install FastAPI and an ASGI server like uvicorn.

pip install fastapi uvicorn python-jose[cryptography]

Creating a Basic FastAPI Application

Create a file called main.py and add the following code to set up a simple FastAPI application:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Welcome to FastAPI!"}

Run your application using the following command:

uvicorn main:app --reload

Now, when you navigate to http://127.0.0.1:8000, you should see the welcome message.

Implementing JWT Authentication

Step 1: User Registration and Login

To implement JWT authentication, we need a way for users to register and log in. Let's create a simple in-memory user store for demonstration purposes.

from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from typing import List
from passlib.context import CryptContext
import jwt
import datetime

# Constants
SECRET_KEY = "your_secret_key"  # Change this in production
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# User model
class User(BaseModel):
    username: str
    email: str | None = None

class UserInDB(User):
    hashed_password: str

# In-memory user store
fake_users_db = {}

# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# FastAPI app
app = FastAPI()

# OAuth2 scheme
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# Endpoint for user registration
@app.post("/register", response_model=User)
async def register(user: UserInDB):
    if user.username in fake_users_db:
        raise HTTPException(status_code=400, detail="Username already registered")
    user.hashed_password = pwd_context.hash(user.hashed_password)
    fake_users_db[user.username] = user
    return user

# Endpoint for user login
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = fake_users_db.get(form_data.username)
    if not user or not pwd_context.verify(form_data.password, user.hashed_password):
        raise HTTPException(status_code=401, detail="Invalid credentials")
    access_token_expires = datetime.timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(data={"sub": user.username}, expires_delta=access_token_expires)
    return {"access_token": access_token, "token_type": "bearer"}

# Function to create a JWT token
def create_access_token(data: dict, expires_delta: datetime.timedelta | None = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.datetime.utcnow() + expires_delta
    else:
        expire = datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

Step 2: Protecting Endpoints with JWT

Now that we have user registration and login functionality, we can secure our API endpoints using JWT.

from fastapi import Security

# Function to get the current user
async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=401,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        return fake_users_db.get(username)
    except jwt.PyJWTError:
        raise credentials_exception

# Protected endpoint
@app.get("/users/me", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

Step 3: Testing the API

  1. Register a User: Send a POST request to /register with a JSON body containing username, email, and hashed_password (hashed using bcrypt).
  2. Login to Get Token: Send a POST request to /token with form data containing username and password. You will receive a JWT in response.
  3. Access Protected Endpoint: Use the JWT as a Bearer token in the Authorization header to access the /users/me endpoint.

Conclusion

Securing your API with JWT authentication in FastAPI is a straightforward process that enhances the security of your applications. By following this guide, you can create a robust authentication system that protects your data and user information. FastAPI's ease of use, combined with the power of JWT, makes it an excellent choice for modern web applications.

Key Takeaways

  • Use FastAPI to create APIs quickly and efficiently.
  • Implement JWT for stateless authentication.
  • Secure endpoints by validating JWTs.

With these tools in your arsenal, you're well-equipped to build secure, high-performance APIs. 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.