FastAPI Day 7: Implementing Clear JWT Authentication with Dependency Injection

This tutorial walks through building a full registration and login system in FastAPI, covering bcrypt password hashing, JWT token creation with expiration, dependency-injected authentication helpers, protected endpoints, and a suite of passing tests, demonstrating a clear and practical approach to backend authentication.

Tech Ocean
Tech Ocean
Tech Ocean
FastAPI Day 7: Implementing Clear JWT Authentication with Dependency Injection

1. Registration: Store Passwords as Hashes

Passwords must never be stored in plain text. The article uses bcrypt to hash passwords.

import bcrypt
def get_password_hash(password: str) -> str:
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
def verify_password(plain: str, hashed: str) -> bool:
    return bcrypt.checkpw(plain.encode(), hashed.encode())

The registration endpoint checks for duplicate email, hashes the password, stores the user record, and returns a public user object.

@app.post("/auth/register", status_code=201)
def register(user: UserCreate):
    if user.email in USERS_DB:
        raise HTTPException(status_code=400, detail="Email already registered")
    hashed = get_password_hash(user.password)
    USERS_DB[user.email] = {"email": user.email, "hashed_password": hashed, ...}
    return UserPublic(email=user.email, full_name=user.full_name)

2. Login: Generate JWT Token

When a user logs in, the password is verified and a JWT token with an expiration time is created.

import jwt
from datetime import datetime, timedelta, timezone

SECRET_KEY = "change-this-in-production"
ALGORITHM = "HS256"

def create_access_token(data: dict, expires_delta: timedelta | None = None):
    to_encode = data.copy()
    expire = datetime.now(timezone.utc) + (expires_delta or timedelta(minutes=30))
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

The login endpoint accepts form data, validates credentials, and returns the access token.

@app.post("/auth/login")
def login(username: str = Form(), password: str = Form()):
    if username not in USERS_DB:
        raise HTTPException(status_code=401, detail="Incorrect credentials")
    user = USERS_DB[username]
    if not verify_password(password, user["hashed_password"]):
        raise HTTPException(status_code=401, detail="Incorrect credentials")
    access_token = create_access_token(data={"sub": username})
    return {"access_token": access_token, "token_type": "bearer"}

3. Protected Routes: Dependency‑Injected Authentication Chain

Endpoints that require authentication add a single dependency:

def get_current_user_from_token(token: Annotated[str, Depends(verify_token)]):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        email = payload.get("sub")
        if email is None:
            raise HTTPException(status_code=401, detail="Invalid token")
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")
    return email

@app.get("/auth/me")
def get_me(current_email: Annotated[str, Depends(get_current_user_from_token)]):
    user = USERS_DB[current_email]
    return UserPublic(email=user["email"], full_name=user["full_name"])

The verify_token dependency (introduced on Day 5) parses the Authorization header; get_current_user_from_token only decodes and validates the token.

4. What Was Completed on Day 7

bcrypt password hashing (store hash, verify on login)

JWT token generation with expiration

POST /auth/register endpoint

POST /auth/login endpoint (form‑encoded)

GET /auth/me protected endpoint using JWT

All five new test cases pass, bringing the total to 47

5. Next Steps

Day 8 will cover database integration with SQLModel and project structuring into routers, models, and schemas.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendPythonAuthenticationDependency InjectionJWTfastapibcrypt
Tech Ocean
Written by

Tech Ocean

Focused on AI programming, sharing ready-to-use development efficiency solutions.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.