2-setting-up-a-secure-api-with-fastapi-and-jwt-authentication.html

Setting Up a Secure API with FastAPI and JWT Authentication

In today’s digital landscape, securing your APIs is not just a best practice; it’s a necessity. With the rise of web applications and mobile services, ensuring that your API endpoints are protected from unauthorized access is paramount. FastAPI, a modern and fast web framework for building APIs with Python, is an excellent tool for this purpose. Coupled with JWT (JSON Web Tokens) for authentication, you can create a secure API that is both efficient and easy to implement.

Understanding FastAPI and JWT

What is FastAPI?

FastAPI is a web framework built on top of Starlette and Pydantic, designed to create APIs quickly and efficiently. It offers numerous features like automatic validation, serialization, and interactive API documentation, all while maintaining high performance.

What is JWT?

JSON Web Token (JWT) is an open standard used for securely transmitting information between parties as a JSON object. It is compact, URL-safe, and can be verified and trusted because it is digitally signed. JWTs are widely used for authentication and information exchange in web applications.

Use Cases for JWT Authentication

  • User Authentication: Verify user identity during login and provide secure access to resources.
  • Session Management: Maintain user sessions without the need for server-side storage.
  • Microservices Communication: Secure communication between different services in a microservices architecture.

Prerequisites

Before we start coding, ensure you have the following installed:

  • Python 3.6 or higher
  • FastAPI
  • Uvicorn (ASGI server)
  • PyJWT (for handling JWTs)
  • Passlib (for password hashing)

You can install the required packages using pip:

pip install fastapi uvicorn pyjwt passlib[bcrypt]

Step-by-Step Guide to Setting Up FastAPI with JWT Authentication

Step 1: Create a Basic FastAPI Application

Begin by creating a new directory for your project and inside it, create a new Python file named main.py.

# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Welcome to FastAPI with JWT Authentication"}

Run your FastAPI application using Uvicorn:

uvicorn main:app --reload

Visit http://127.0.0.1:8000 in your browser to see your running API.

Step 2: Implement User Registration and Password Hashing

To handle user authentication, you need a way to register users and securely store their passwords. Use Passlib to hash passwords.

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from passlib.context import CryptContext

app = FastAPI()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

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

users_db = {}

def hash_password(password: str):
    return pwd_context.hash(password)

@app.post("/register")
def register(user: User):
    if user.username in users_db:
        raise HTTPException(status_code=400, detail="Username already registered")
    users_db[user.username] = hash_password(user.password)
    return {"message": "User registered successfully"}

Step 3: Create JWT Token Generation

Next, you’ll need to create a function that generates JWT tokens for authenticated users.

import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"

def create_jwt_token(username: str):
    expiration = datetime.utcnow() + timedelta(hours=1)
    token = jwt.encode({"sub": username, "exp": expiration}, SECRET_KEY, algorithm=ALGORITHM)
    return token

Step 4: Implement User Login and JWT Issuance

Now, let’s implement the user login endpoint that verifies credentials and issues a JWT token.

@app.post("/login")
def login(user: User):
    if user.username not in users_db or not pwd_context.verify(user.password, users_db[user.username]):
        raise HTTPException(status_code=401, detail="Invalid credentials")

    token = create_jwt_token(user.username)
    return {"access_token": token, "token_type": "bearer"}

Step 5: Protecting Routes with JWT Authentication

To secure your API endpoints, you’ll need to create a dependency that checks for a valid JWT token.

from fastapi import Depends, Security
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")

def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise HTTPException(status_code=401, detail="Invalid authentication credentials")
        return username
    except jwt.PyJWTError:
        raise HTTPException(status_code=401, detail="Invalid authentication credentials")

Step 6: Creating Protected Endpoints

You can now create endpoints that require authentication.

@app.get("/users/me", response_model=User)
def read_users_me(current_user: str = Depends(get_current_user)):
    return {"username": current_user}

Conclusion

By following these steps, you've successfully set up a secure API using FastAPI and JWT authentication. With this foundation, you can expand your application to include more features, such as user roles, refresh tokens, and more sophisticated permission checks.

Key Takeaways

  • FastAPI simplifies API development with its built-in features.
  • JWT provides a secure way to handle user authentication.
  • Properly hashing passwords is crucial for security.

As you advance in your FastAPI journey, remember to keep security at the forefront of your development process. 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.