2-creating-a-secure-api-with-fastapi-and-oauth2-authentication.html

Creating a Secure API with FastAPI and OAuth2 Authentication

In today's digital landscape, securing APIs is paramount. As developers, we need to ensure that our applications protect sensitive data and user information. FastAPI, a modern web framework for building APIs with Python, offers a robust solution for creating secure endpoints. In this article, we'll explore how to implement OAuth2 authentication in a FastAPI application, providing you with step-by-step instructions, code snippets, and actionable insights.

What is FastAPI?

FastAPI is a high-performance framework for building APIs with Python 3.6+ based on standard Python type hints. It is designed to be easy to use while providing features like automatic generation of OpenAPI documentation and support for asynchronous programming. FastAPI is particularly suited for building RESTful APIs and microservices due to its speed and efficiency.

Understanding OAuth2 Authentication

OAuth2 is an authorization framework that allows third-party applications to obtain limited access to an HTTP service. It is widely used for securing APIs and protecting user data. The OAuth2 protocol defines several flows for different use cases, such as:

  • Authorization Code Flow: Ideal for server-side applications.
  • Implicit Flow: Used in browser-based applications.
  • Resource Owner Password Credentials Flow: For trusted applications.
  • Client Credentials Flow: Used for machine-to-machine communication.

In this article, we will focus on implementing the Authorization Code Flow with FastAPI, which is the most secure and commonly used method for web applications.

Setting Up Your FastAPI Environment

Before we dive into the code, let's set up a basic FastAPI project.

Step 1: Install FastAPI and Required Packages

Make sure you have Python installed on your machine. Then, you can install FastAPI and a few other necessary packages via pip:

pip install fastapi uvicorn python-multipart python-jose
  • fastapi: The core framework.
  • uvicorn: An ASGI server for running FastAPI applications.
  • python-multipart: For handling form data.
  • python-jose: For creating and verifying JSON Web Tokens (JWTs).

Step 2: Create the Project Structure

Create a directory for your FastAPI application and navigate to it:

mkdir fastapi_oauth2
cd fastapi_oauth2

Inside this directory, create a file named main.py. This will be the main entry point of your application.

Implementing OAuth2 in FastAPI

Step 3: Create the FastAPI Application

In main.py, import the necessary modules and create a FastAPI instance:

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

app = FastAPI()

Step 4: Define Security Parameters

Next, set up the OAuth2 password bearer and JWT settings:

# Define the secret key and algorithm
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

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

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

Step 5: User Authentication Functions

Now, let's create functions to handle user authentication and token generation:

# Fake user data for demonstration purposes
fake_users_db = {
    "user@example.com": {
        "username": "user@example.com",
        "full_name": "John Doe",
        "email": "user@example.com",
        "hashed_password": pwd_context.hash("password"),
        "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:
        return db[username]
    return None

def create_access_token(data: dict, expires_delta: Optional[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

Step 6: Create the Token Endpoint

Now, let's create a token endpoint that allows users to log in and receive a JWT:

@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 7: Protect Routes with OAuth2

With the token endpoint in place, we can now create a protected route:

@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 JWTError:
        raise credentials_exception
    user = get_user(fake_users_db, username)
    if user is None:
        raise credentials_exception
    return user

Step 8: Run Your Application

Finally, run your FastAPI application using Uvicorn:

uvicorn main:app --reload

Your API is now up and running! You can test the /token endpoint to obtain a token and then access the /users/me endpoint using that token.

Conclusion

In this article, we demonstrated how to create a secure API using FastAPI with OAuth2 authentication. By implementing JWTs, we can ensure that only authorized users can access sensitive data. FastAPI's intuitive design and powerful features make it an excellent choice for building secure APIs.

Key Takeaways:

  • FastAPI simplifies the process of building APIs with built-in support for security.
  • OAuth2 provides a robust authentication mechanism suitable for modern applications.
  • Using JWTs enhances the security of your API by allowing stateless authentication.

By following the steps outlined in this guide, you can create your own secure API with FastAPI and OAuth2 authentication, laying the groundwork for developing more complex and powerful applications. 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.