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

Creating a Secure API with FastAPI and JWT Authentication

In today's digital landscape, APIs have become the backbone of modern applications, enabling seamless communication between different services. However, with increased connectivity comes the necessity for robust security measures. This article will guide you through creating a secure API using FastAPI, one of the most popular web frameworks for building APIs in Python, combined with JWT (JSON Web Token) authentication.

What is FastAPI?

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. It is designed to create RESTful APIs quickly and efficiently, and its automatic generation of interactive API documentation (thanks to OpenAPI) makes it a favorite among developers.

What is JWT Authentication?

JSON Web Tokens (JWT) are an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs are widely used for authentication and information exchange due to their compact size and ease of use.

Use Cases for FastAPI and JWT

  • User Authentication: Securely manage user sessions and protect routes.
  • Microservices: Facilitate communication between microservices in a secure manner.
  • Mobile Applications: Provide backend support for mobile apps with secure API calls.

Setting Up the Environment

Before we dive into the code, ensure you have Python installed (3.6 or higher). You can create a virtual environment and install FastAPI and the necessary libraries using pip:

# Create a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows use `venv\Scripts\activate`

# Install FastAPI and Uvicorn
pip install fastapi uvicorn python-jose[cryptography] passlib[bcrypt]

Step-by-Step Implementation

1. Create the FastAPI Application

Start by creating a new Python file, main.py, and import the necessary libraries.

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from jose import JWTError, jwt
from datetime import datetime, timedelta
from passlib.context import CryptContext

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

# Create FastAPI instance
app = FastAPI()

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

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

2. Define Data Models

Next, define the data models for your application using Pydantic. This helps with data validation and serialization.

class User(BaseModel):
    username: str
    email: str
    full_name: str = None
    disabled: bool = None

class UserInDB(User):
    hashed_password: str

class Token(BaseModel):
    access_token: str
    token_type: str

class TokenData(BaseModel):
    username: str

3. User Management

Create a mock database of users and methods for password hashing, user retrieval, and token creation.

# Mock database
fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "full_name": "John Doe",
        "email": "johndoe@example.com",
        "hashed_password": pwd_context.hash("secret"),
        "disabled": False,
    }
}

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return UserInDB(**user_dict)

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

4. Authentication Logic

Implement the login route that generates the JWT token upon successful authentication.

@app.post("/token", response_model=Token)
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = get_user(fake_users_db, form_data.username)
    if not user or not verify_password(form_data.password, user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = 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"}

5. Protecting Routes

Now, create a protected route that requires a valid JWT token.

@app.get("/users/me", response_model=User)
async def read_users_me(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        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
        token_data = TokenData(username=username)
    except JWTError:
        raise credentials_exception
    user = get_user(fake_users_db, token_data.username)
    if user is None:
        raise credentials_exception
    return user

6. Running the Application

To run your FastAPI application, execute the following command in your terminal:

uvicorn main:app --reload

Visit http://127.0.0.1:8000/docs to see the interactive API documentation generated by FastAPI.

Conclusion

Creating a secure API with FastAPI and JWT authentication is straightforward and effective. By following the steps outlined in this article, you can implement a robust authentication mechanism that ensures your API is secure. Whether you’re building a small application or a large enterprise solution, FastAPI provides the tools needed to manage user authentication seamlessly.

Now that you have a foundational understanding of FastAPI and JWT, consider expanding on this by implementing user registration, database storage, and more sophisticated user management features. The possibilities are endless!

SR
Syed
Rizwan

About the Author

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