how-to-create-a-secure-api-with-oauth-20-in-a-fastapi-application.html

How to Create a Secure API with OAuth 2.0 in a FastAPI Application

In today’s digital landscape, securing APIs is crucial for protecting sensitive data and ensuring that only authorized users can access certain functionalities. One of the most widely adopted methodologies for securing APIs is OAuth 2.0. FastAPI, a modern, fast (high-performance) web framework for building APIs with Python 3.6+ based on standard Python-type hints, makes it relatively easy to implement OAuth 2.0 for your applications. In this article, we will guide you through the process of creating a secure API with OAuth 2.0 in a FastAPI application, complete with code snippets and step-by-step instructions.

What is OAuth 2.0?

OAuth 2.0 is an authorization framework that allows third-party services to exchange limited access to user accounts without revealing passwords. It is widely used in various applications, including social media logins and other authentication services.

Key Concepts of OAuth 2.0

  • Resource Owner: The user who authorizes an application to access their account.
  • Client: The application wanting to access the user’s account.
  • Authorization Server: The server that authenticates the user and issues access tokens.
  • Resource Server: The server hosting the user’s resources (APIs).

Use Cases for OAuth 2.0

  • Third-party logins: Allow users to sign in with their Google or Facebook accounts.
  • API access: Grant clients limited access to user data on behalf of the user.

Setting Up FastAPI

Before we dive into OAuth 2.0, let’s set up a basic FastAPI application. Start by installing FastAPI and an ASGI server, such as Uvicorn:

pip install fastapi uvicorn python-multipart

Next, create a simple FastAPI application.

Basic FastAPI Application Structure

# main.py
from fastapi import FastAPI

app = FastAPI()

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

Run your FastAPI application with the following command:

uvicorn main:app --reload

Implementing OAuth 2.0

Now that we have a basic FastAPI application, let’s implement OAuth 2.0. We will use the fastapi.security module, which provides several utilities for working with security schemes.

Step 1: Import Required Modules

First, import the necessary modules for OAuth 2.0. We will need OAuth2PasswordBearer for token handling and OAuth2PasswordRequestForm for form data.

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

Step 2: Create User and Token Models

Define the models for user credentials and tokens.

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

class UserInDB(User):
    hashed_password: str

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

Step 3: Setting Up OAuth2PasswordBearer

Set up the OAuth2PasswordBearer, which will be used to extract the token from the request.

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

Step 4: Create a Fake Database

For the sake of this example, we'll create a fake in-memory user database.

fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "full_name": "John Doe",
        "email": "johndoe@example.com",
        "hashed_password": "$2b$12$KIXsZyP/1F5F/2P7Uqntd.Gy0yI9FZtKXGTd9wm5lF8OBtE4tQ8cS",
        "disabled": False,
    }
}

Step 5: Password Hashing and Verification

Implement functions for hashing passwords and verifying them.

from passlib.context import CryptContext

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

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

def get_password_hash(password):
    return pwd_context.hash(password)

Step 6: Authenticate Users

Create a function to authenticate users using their credentials.

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

Step 7: Create Token Endpoint

Now, create the /token endpoint that clients can use to obtain an access token.

from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordRequestForm

@app.post("/token", response_model=Token)
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, 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 = "dummy_access_token"  # Replace with a real token generation logic
    return {"access_token": access_token, "token_type": "bearer"}

Step 8: Protect API Endpoints

Finally, protect your API endpoints using the access token.

@app.get("/users/me", response_model=User)
async def read_users_me(token: str = Depends(oauth2_scheme)):
    # Here you would decode and validate the token to get the user
    return fake_users_db["johndoe"]  # Replace with actual user data retrieval

Conclusion

In this article, we walked through creating a secure API with OAuth 2.0 in a FastAPI application. By following these steps, you now have a basic structure that you can build upon, adding more functionality as needed.

Key Takeaways:

  • OAuth 2.0 allows secure access to user data without sharing passwords.
  • FastAPI simplifies the implementation of OAuth 2.0 with its built-in security utilities.
  • Always ensure your tokens are securely generated and validated.

Now, it’s your turn to implement and test your secure API! 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.