Table of Contents
FastAPI is a modern, fast (high-performance) web framework for building APIs with Python. When developing secure applications, testing authentication endpoints is crucial to ensure that only authorized users can access protected resources. In this article, we will explore how to test FastAPI authentication endpoints using pytest and HTTPX, a powerful HTTP client for Python.
Setting Up the Environment
Before diving into tests, ensure you have the necessary libraries installed. You will need FastAPI, pytest, and HTTPX. You can install them using pip:
pip install fastapi uvicorn pytest httpx
FastAPI applications are typically run with Uvicorn, an ASGI server. For testing purposes, you can run your app in the background or use TestClient provided by FastAPI. However, for more realistic tests, HTTPX’s AsyncClient is preferred.
Creating a Sample FastAPI Authentication Endpoint
Here’s a simple FastAPI app with a login endpoint that issues a JWT token upon successful authentication:
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from jose import JWTError, jwt
app = FastAPI()
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
def authenticate_user(username: str, password: str):
if username == "user" and password == "pass":
return {"username": username}
return None
@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",
)
token_data = {"sub": user["username"]}
token = jwt.encode(token_data, SECRET_KEY, algorithm=ALGORITHM)
return {"access_token": token, "token_type": "bearer"}
Writing Tests with pytest and HTTPX
To test the authentication endpoint, we’ll simulate login requests with valid and invalid credentials. HTTPX’s AsyncClient allows us to perform asynchronous HTTP requests efficiently.
import pytest
from httpx import AsyncClient
from main import app # Assuming your FastAPI app is in main.py
@pytest.mark.anyio
async def test_login_success():
async with AsyncClient(app=app, base_url="http://test") as ac:
response = await ac.post("/token", data={"username": "user", "password": "pass"})
assert response.status_code == 200
json_response = response.json()
assert "access_token" in json_response
assert json_response["token_type"] == "bearer"
@pytest.mark.anyio
async def test_login_failure():
async with AsyncClient(app=app, base_url="http://test") as ac:
response = await ac.post("/token", data={"username": "user", "password": "wrong"})
assert response.status_code == 401
json_response = response.json()
assert json_response["detail"] == "Incorrect username or password"
Running the Tests
Execute your tests using pytest. Make sure your FastAPI app is accessible or use the TestClient as shown. Run the command:
pytest --asyncio
Pytest will automatically discover and run your asynchronous tests, verifying that your authentication endpoints behave as expected.
Conclusion
Testing FastAPI authentication endpoints with pytest and HTTPX provides a robust way to ensure your security mechanisms work correctly. By simulating real login requests and verifying responses, you can catch issues early and maintain a secure API.