0
0
FastapiHow-ToBeginner · 4 min read

How to Use Passlib with FastAPI for Secure Password Hashing

Use passlib.context.CryptContext in FastAPI to hash passwords securely and verify them during login. Create a CryptContext instance with a hashing scheme like bcrypt, then use its hash() and verify() methods to handle passwords safely.
📐

Syntax

To use Passlib with FastAPI, first create a CryptContext object specifying the hashing algorithms. Then use hash() to create a hashed password and verify() to check a plain password against the hash.

  • CryptContext(schemes=[...]): Defines which hash algorithms to use.
  • hash(password): Hashes the plain password.
  • verify(plain_password, hashed_password): Checks if the plain password matches the hash.
python
from passlib.context import CryptContext

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

# Hash a password
hashed_password = pwd_context.hash("mysecretpassword")

# Verify a password
is_valid = pwd_context.verify("mysecretpassword", hashed_password)
💻

Example

This example shows a simple FastAPI app that hashes a password on signup and verifies it on login using Passlib's CryptContext. It demonstrates secure password handling without storing plain text passwords.

python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from passlib.context import CryptContext

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

fake_user_db = {}

class User(BaseModel):
    username: str
    password: str

@app.post("/signup")
async def signup(user: User):
    if user.username in fake_user_db:
        raise HTTPException(status_code=400, detail="User already exists")
    hashed_password = pwd_context.hash(user.password)
    fake_user_db[user.username] = hashed_password
    return {"msg": "User created successfully"}

@app.post("/login")
async def login(user: User):
    hashed_password = fake_user_db.get(user.username)
    if not hashed_password or not pwd_context.verify(user.password, hashed_password):
        raise HTTPException(status_code=401, detail="Invalid username or password")
    return {"msg": "Login successful"}
⚠️

Common Pitfalls

  • Not using a CryptContext and hashing passwords manually can lead to insecure implementations.
  • Storing plain text passwords instead of hashed versions is a serious security risk.
  • Using outdated or weak hashing algorithms instead of modern ones like bcrypt or argon2.
  • Forgetting to verify passwords properly during login causes authentication failures.

Always use CryptContext with a recommended scheme and verify passwords with its verify() method.

python
from passlib.context import CryptContext

# Wrong: Storing plain password
plain_password = "mypassword"
stored_password = plain_password  # insecure!

# Right: Hashing password
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
stored_password = pwd_context.hash(plain_password)

# Wrong: Verifying by direct string compare
is_valid = (plain_password == stored_password)  # always False

# Right: Use verify method
is_valid = pwd_context.verify(plain_password, stored_password)
📊

Quick Reference

  • CryptContext(schemes=["bcrypt"]): Create password hashing context.
  • hash(password): Hash a plain password.
  • verify(plain, hashed): Check if plain password matches hash.
  • Use bcrypt or argon2 for strong security.
  • Never store or compare plain passwords directly.

Key Takeaways

Always hash passwords using Passlib's CryptContext before storing them.
Use the verify() method to check passwords securely during login.
Choose strong hashing schemes like bcrypt or argon2 in CryptContext.
Never store or compare plain text passwords directly.
Integrate Passlib with FastAPI to keep user authentication safe and simple.