securing-fastapi-applications-with-oauth2-and-jwt-authentication.html

Securing FastAPI Applications with OAuth2 and JWT Authentication

FastAPI is an incredibly powerful modern web framework for building APIs with Python. Its speed and ease of use have made it a go-to choice for developers looking to create robust applications. However, as with any web application, security is a paramount concern. In this article, we will explore how to secure FastAPI applications using OAuth2 and JWT (JSON Web Tokens) authentication.

Understanding OAuth2 and JWT

What is OAuth2?

OAuth2 is an authorization framework that allows third-party applications to obtain limited access to an HTTP service. This process is carried out without sharing user credentials. Instead, OAuth2 uses access tokens to grant permission to access user data.

What is JWT?

JWT, or JSON Web Token, is a compact way to represent claims securely between two parties. It contains a set of claims that can be verified and trusted using a digital signature. JWTs are commonly used for authentication and information exchange in web applications.

Use Cases for OAuth2 and JWT in FastAPI

  • User Authentication: Secure user authentication for web and mobile applications.
  • API Security: Protect RESTful APIs by ensuring only authorized users can access certain endpoints.
  • Single Sign-On (SSO): Enable users to log into multiple applications with a single set of credentials.
  • Third-Party Integrations: Allow third-party applications to access user data without compromising security.

Setting Up FastAPI with OAuth2 and JWT

Prerequisites

Before diving into the code, ensure you have the following installed:

  • Python 3.7 or higher
  • FastAPI (pip install fastapi)
  • Uvicorn (pip install uvicorn)
  • Python JWT library (pip install PyJWT)
  • Passlib for password hashing (pip install passlib[bcrypt])

Step 1: Basic FastAPI Setup

First, let’s create a simple FastAPI application.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

Run the application:

uvicorn main:app --reload

Step 2: Implementing OAuth2 and JWT

Next, we will implement OAuth2 with Password Flow and use JWT for handling authentication tokens.

Defining User Models

Create a model for user credentials and user data.

from pydantic import BaseModel

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

class UserInDB(User):
    hashed_password: str

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

Password Hashing

Securely hash user passwords using Passlib.

from passlib.context import CryptContext

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

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

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

JWT Creation and Validation

Now, let’s create functions to generate and validate JWTs.

import jwt
from datetime import datetime, timedelta

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

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=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

Step 3: Creating the Authentication Endpoint

Now, let’s create an endpoint for user login.

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "full_name": "John Doe",
        "email": "johndoe@example.com",
        "hashed_password": hash_password("secret"),
        "disabled": False,
    }
}

def authenticate_user(username: str, password: str):
    user = fake_users_db.get(username)
    if not user or not verify_password(password, user['hashed_password']):
        return False
    return user

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token = create_access_token(data={"sub": user['username']})
    return {"access_token": access_token, "token_type": "bearer"}

Step 4: Protecting API Endpoints

Finally, let’s secure a sample endpoint using the generated JWT.

from fastapi import Security

@app.get("/users/me")
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
    except jwt.PyJWTError:
        raise credentials_exception
    user = fake_users_db.get(username)
    return user

Conclusion

Securing FastAPI applications with OAuth2 and JWT authentication is not only essential for protecting user data but also for maintaining the integrity of your application. By following the steps outlined in this article, you can implement a robust authentication system that ensures your API is secure and user-friendly.

Key Takeaways

  • OAuth2 offers a secure way to grant access to resources without exposing user credentials.
  • JWT serves as an efficient method for transmitting claims securely.
  • FastAPI simplifies the implementation process with built-in dependencies for handling OAuth2.
  • Always hash passwords and validate them securely to protect user data.

With these insights and code examples, you can confidently implement OAuth2 and JWT in your FastAPI applications, ensuring your users’ data remains secure and integrity is maintained. 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.