4-building-secure-apis-with-oauth2-and-fastapi-for-python-developers.html

Building Secure APIs with OAuth2 and FastAPI for Python Developers

In today's tech-driven world, APIs (Application Programming Interfaces) are the backbone of many applications, enabling seamless data exchange between services. As a Python developer, one of the most critical aspects of building APIs is ensuring their security. In this article, we’ll explore how to implement secure APIs using OAuth2 in conjunction with FastAPI, a modern, fast web framework for building APIs with Python 3.6+.

What is OAuth2?

OAuth2 is an authorization framework that allows third-party applications to obtain limited access to user accounts on an HTTP service. It provides a way for users to grant access to their information while keeping their credentials safe. By separating the roles of the user, the application, and the resource server, OAuth2 enables secure, token-based authorization.

Key Concepts of OAuth2

  • Access Token: A token that the client application uses to access protected resources.
  • Refresh Token: A token used to obtain a new access token once it expires.
  • Authorization Grant: The way a client gains access to the resource owner’s data, such as through user credentials or authorization codes.

Why Use FastAPI for Building APIs?

FastAPI is an excellent choice for building APIs because:

  • Speed: It is one of the fastest Python frameworks available, thanks to its use of Starlette for the web parts and Pydantic for data validation.
  • Easy to Use: FastAPI is user-friendly, making it straightforward to create APIs quickly.
  • Automatic Documentation: It generates interactive API documentation automatically, allowing you to test endpoints easily.

Setting Up Your FastAPI Project

Step 1: Install FastAPI and Dependencies

Start by installing FastAPI and an ASGI server, like Uvicorn, for running your application:

pip install fastapi uvicorn python-jose[cryptography] passlib[bcrypt]
  • python-jose: A library for handling JWTs (JSON Web Tokens).
  • passlib: Used for password hashing.

Step 2: Create a Basic FastAPI Application

Let’s create a simple FastAPI application with basic endpoint definitions.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Welcome to the secure API!"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Step 3: Implement OAuth2

Now, let’s integrate OAuth2 into our FastAPI application. We will create a simple authentication system that uses tokens.

3.1: User Management

First, you need a basic user management system. For simplicity, we’ll use an in-memory dictionary to store user data. In a production environment, consider using a database.

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from passlib.context import CryptContext

# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "full_name": "John Doe",
        "email": "johndoe@example.com",
        "hashed_password": pwd_context.hash("secret"),
        "disabled": False,
    }
}

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

3.2: Authentication Functions

Next, define functions to verify user credentials and create access tokens.

from jose import JWTError, jwt
from datetime import datetime, timedelta

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

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:
        return db[username]
    return None

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

3.3: Token Endpoint

Now, create an endpoint to issue tokens when users provide valid credentials.

@app.post("/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"}

Step 4: Protecting Your Endpoints

To protect your API routes using OAuth2, use the oauth2_scheme dependency.

@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    # Decode the token to get user information
    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 JWTError:
        raise credentials_exception
    user = get_user(fake_users_db, username)
    if user is None:
        raise credentials_exception
    return user

Conclusion

Building secure APIs with OAuth2 and FastAPI allows developers to create robust applications that protect user data while providing easy access to authorized resources. By following the steps outlined in this article, you can create a basic yet secure API framework that can be expanded with additional features and functionalities.

Key Takeaways

  • OAuth2: A robust authorization framework for secure API access.
  • FastAPI: A modern, fast framework for building APIs with automatic documentation.
  • Token-based Authentication: Use access tokens to protect routes and manage user sessions securely.

As you continue to develop your API, consider implementing additional features like user registration, password reset functionality, and integrating a database for persistent user management. 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.