FastAPI: From Basics to Production · Authentication and Security

Password Hashing and the Login Endpoint

Hash passwords with Argon2 and implement OAuth2 password flow login.

Store passwords with a slow, salted hash: the FastAPI docs now use pwdlib with Argon2 (passlib is unmaintained). Implement login with OAuth2PasswordRequestForm (form fields username and password) so Swagger UI's "Authorize" button works. Return the same error for unknown users and wrong passwords, and rate-limit the endpoint.

from typing import Annotated
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from pwdlib import PasswordHash

password_hash = PasswordHash.recommended()     # Argon2


def hash_password(raw: str) -> str:
    return password_hash.hash(raw)


@app.post("/auth/token")
async def login(form: Annotated[OAuth2PasswordRequestForm, Depends()], db: DB) -> TokenOut:
    user = await users.by_email(db, form.username)
    if user is None or not password_hash.verify(form.password, user.password_hash):
        raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Incorrect email or password",
                            headers={"WWW-Authenticate": "Bearer"})
    return TokenOut(access_token=create_access_token(user), token_type="bearer")

Common pitfalls

  • Different errors for unknown email vs wrong password (account enumeration).
  • Fast hashes like SHA-256 for passwords.
  • No rate limiting on the login route.

Key points

  • Argon2 via pwdlib
  • OAuth2PasswordRequestForm for login
  • Generic errors and rate limits

Further reading: FastAPI: OAuth2 with password and JWT

Practice questions

Why does the login endpoint use form data instead of JSON?

Answer

The OAuth2 password flow spec sends username and password as form fields; following it makes Swagger UI's Authorize dialog and OAuth2 clients work out of the box.

Why is SHA-256 unsuitable for passwords?

Answer

It's designed to be fast, so attackers can test billions of guesses per second; Argon2/bcrypt are deliberately slow and memory-hard.

Open in the app to mark lessons complete, take notes and track your progress.