FastAPI Security Essentials: OAuth2, JWT, and Third-Party Integrations

Tom
5 min readAug 21, 2024

Understanding the Basics: Authentication vs. Authorization

Before diving deep into the intricacies of securing a FastAPI application, it’s crucial to distinguish between authentication and authorization. Though often used interchangeably, these terms address different aspects of security.

Authentication identifies who the user is. It’s the process of verifying the identity of a user. This might involve checking a password, using OAuth2 tokens, or relying on third-party providers like Google or Facebook.

Authorization, on the other hand, determines what an authenticated user is allowed to do. This process entails setting permissions to ensure users can only access data and perform actions they’re permitted to.

Grasping these fundamental concepts provides a firm foundation for the more technical aspects discussed later.

Getting Started with FastAPI: The Setup

FastAPI simplifies building APIs with Python, and setting up authentication and authorization is no exception. To begin, ensure you have FastAPI and Uvicorn installed:

pip install fastapi uvicorn

Next, create a basic FastAPI app setup:

from fastapi import FastAPI

app = FastAPI()

@app.get(“/”)

def read_root():

return {“Hello”: “World”}

This script sets up a minimal app. To run it, use the following command:

uvicorn main:app — reload

Visit http://127.0.0.1:8000/ to see the running app.

OAuth2 Simplified: Adding OAuth2 to Your FastAPI Project

OAuth2 provides a secure way to handle user authentication. FastAPI includes support for OAuth2 with Password (and hashing), OAuth2 with Password and Bearer token, and various utilities to make this process as smooth as possible.

Here’s a simplified example of using OAuth2 with a password flow:

  1. Add Dependencies: First, include an additional package for password hashing.

pip install passlib[bcrypt]

  1. Create OAuth2PasswordBearer: Define the OAuth2 scheme and authentication route:

from fastapi import Depends

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl=”token”)

@app.post(“/token”)

async def token():

return {“access_token”: “fake-token”, “token_type”: “bearer”}

  1. Secure Your Routes: Apply the OAuth2 scheme to your routes.

from fastapi import Security

@app.get(“/users/me”)

async def read_users_me(token: str = Depends(oauth2_scheme)):

return {“token”: token}

This example demonstrates the basics, but a typical application would validate tokens and keep user data secure.

Securing Endpoints with JWT Tokens: A Step-by-Step Guide

Using JWT (JSON Web Tokens) is a common technique for securing web applications. It involves issuing a compact, URL-safe token that clients can use to prove their authentication status.

Generate and Verify JWT Tokens:

  1. Install PyJWT:

pip install pyjwt

  1. Create Utility Functions:

import jwt

from datetime import datetime, timedelta

SECRET_KEY = “your-secret-key”

ALGORITHM = “HS256”

def create_access_token(data: dict):

to_encode = data.copy()

expire = datetime.utcnow() + timedelta(minutes=30)

to_encode.update({“exp”: expire})

encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

return encoded_jwt

def decode_access_token(token: str):

try:

payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])

return payload

except jwt.PyJWTError:

return None

  1. Integrate with OAuth2:

@app.post(“/token”)

async def login(form_data: OAuth2PasswordRequestForm = Depends()):

user_dict = {“sub”: form_data.username}

access_token = create_access_token(data=user_dict)

return {“access_token”: access_token, “token_type”: “bearer”}

@app.get(“/users/me”)

async def read_users_me(token: str = Depends(oauth2_scheme)):

payload = decode_access_token(token)

if payload:

username = payload.get(“sub”)

return {“username”: username}

return {“error”: “Invalid token”}

Integrating Third-Party Authentication Providers in FastAPI

Using third-party providers can streamline user authentication. Services like Google, Facebook, and GitHub offer OAuth2 integration which can be incorporated into a FastAPI project.

Example with Google OAuth2:

  1. Register Your App with Google: Obtain a client ID and client secret.
  2. Install Authlib:

pip install authlib

  1. Setup OAuth Client:

from authlib.integrations.starlette_client import OAuth

from fastapi import Request, Depends, HTTPException

oauth = OAuth()

oauth.register(

name=’google’,

client_id=’YOUR_CLIENT_ID’,

client_secret=’YOUR_CLIENT_SECRET’,

authorize_url=’https://accounts.google.com/o/oauth2/auth',

authorize_params=None,

access_token_url=’https://accounts.google.com/o/oauth2/token',

access_token_params=None,

refresh_token_url=None,

redirect_uri=’YOUR_REDIRECT_URI’,

client_kwargs={‘scope’: ‘openid profile email’}

)

@app.route(‘/login’)

async def login(request: Request):

redirect_uri = url_for(‘auth’, _external=True)

return await oauth.google.authorize_redirect(request, redirect_uri)

@app.route(‘/auth’)

async def auth(request: Request):

token = await oauth.google.authorize_access_token(request)

user = token[‘userinfo’]

return user

This example outlines the essential steps. Depending on the provider, details may vary, but the core principles remain consistent.

Managing User Permissions: Roles and Scopes in FastAPI

Managing user permissions involves assigning roles and defining access scopes. Integrating roles ensures that users can only access what they’re permitted to.

Define Roles and Scopes:

from pydantic import BaseModel

class User(BaseModel):

username: str

role: str

users_db = {

“alice”: {“username”: “alice”, “role”: “admin”},

“bob”: {“username”: “bob”, “role”: “user”},

}

def get_current_user(token: str = Depends(oauth2_scheme)):

payload = decode_access_token(token)

if payload:

username = payload.get(“sub”)

if username in users_db:

return User(**users_db[username])

raise HTTPException(status_code=401, detail=”Invalid credentials”)

def admin_required(user: User = Depends(get_current_user)):

if user.role != “admin”:

raise HTTPException(status_code=403, detail=”Not enough permissions”)

return user

@app.get(“/admin”, dependencies=[Depends(admin_required)])

async def read_admin_data():

return {“msg”: “Welcome Admin”}

This segment emphasizes securing user roles by requiring admin roles for certain routes.

Building a Custom Authentication Backend for Your Application

While third-party solutions cover most needs, custom backends may be necessary for unique requirements. This process involves writing your own backend system:

Create a Custom Backend:

  1. User Database and Model:

from pydantic import BaseModel

class UserInDB(BaseModel):

username: str

hashed_password: str

fake_users_db = {

“alice”: UserInDB(username=”alice”, hashed_password=”hashedalicepassword”)

}

  1. Custom Authentication Logic:

from passlib.context import CryptContext

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

def fake_hash_password(password: str):

return pwd_context.hash(password)

def get_password_hash(password: str):

return fake_hash_password(password)

def verify_password(plain_password, hashed_password):

return pwd_context.verify(plain_password, hashed_password)

def authenticate_user(username: str, password: str):

user = fake_users_db.get(username)

if user and verify_password(password, user.hashed_password):

return user

return None

@app.post(“/token”)

async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):

user = authenticate_user(form_data.username, form_data.password)

if not user:

raise HTTPException(

status_code=400, detail=”Incorrect username or password”

)

access_token = create_access_token(data={“sub”: user.username})

return {“access_token”: access_token, “token_type”: “bearer”}

Implementing Password Encryption and Secure Storage

Security best practices dictate the use of strong hashing algorithms for password storage. FastAPI supports this with the passlib library:

  1. Install Passlib:

pip install passlib

  1. Hash and Verify Passwords:

from passlib.context import CryptContext

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

def get_password_hash(password: str):

return pwd_context.hash(password)

def verify_password(plain_password, hashed_password):

return pwd_context.verify(plain_password, hashed_password)

  1. Secure Storage Configuration:

user_password = get_password_hash(“mysecretpassword”)

is_verified = verify_password(“mysecretpassword”, user_password)

print(is_verified) # Should return True

Real-Time Authentication: Using WebSockets in FastAPI

WebSockets add the capability for real-time interaction. FastAPI can secure WebSocket endpoints just like with HTTP:

Secure WebSocket Connection:

from fastapi import WebSocket

@app.websocket(“/ws/{token}”)

async def websocket_endpoint(websocket: WebSocket, token: str):

await websocket.accept()

payload = decode_access_token(token)

if not payload:

await websocket.close(code=4001)

else:

await websocket.send_text(“Connected!”)

# In your front-end JavaScript:

# let socket = new WebSocket(“ws://localhost:8000/ws/” + token);

Case Study: A Real-World Implementation of Auth in FastAPI

Exploring real-world applications provides practical insights. Let’s consider a scenario where an e-commerce platform uses FastAPI for customer and admin authentication.

Customer Authentication Flow:

  • Registration: Capture user details and store hashed passwords.
  • Login: Validate user credentials and issue JWT tokens.
  • Profile Management: Secure endpoints with tokens to manage user profiles.

Admin Panel:

  • Admin Roles: Assign admin roles with elevated privileges.
  • Secure Routes: Implement role-based permissions to restrict access to admin-only routes.

Best Practices for Maintaining Secure Auth Systems in FastAPI

Securing authentication and authorization entails following industry standards and best practices:

  • Use Strong Hashing Algorithms: Leverage libraries like bcrypt.
  • Regularly Rotate Secrets: Update your secret keys periodically.
  • Implement Rate Limiting: Protect against brute force attacks.
  • Use HTTPS: Ensure encrypted communication.
  • Keep Dependencies Updated: Regularly update your libraries.

By following these guidelines, developers can enhance the security and robustness of their FastAPI applications.

Ready to elevate your Python skills? Transform from a beginner to a professional in just 30 days! Get your copy of ‘Python Mastery: From Beginner to Professional in 30 Days’ and start your journey to becoming a Python expert. Visit https://www.amazon.com/dp/B0DCL1F5J2 to get your copy today!

Explore more at Tom Austin’s Hub! Discover a wealth of insights, resources, and inspiration at Tom Austin’s Website. Whether you’re looking to deepen your understanding of technology, explore creative projects, or find something new and exciting, our site has something for everyone. Visit us today and start your journey!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Written by Tom

IT Specialist with 10+ years in PowerShell, Office 365, Azure, and Python. UK-based author simplifying IT concepts. Freelance photographer with a creative eye.

No responses yet

Write a response