FastAPI A to Z Course with ChatGPT

🚀 Lesson 5 — Authentication & Authorization in FastAPI (JWT, OAuth2, Password Hashing)

This is one of the most important and most asked things in FastAPI interviews and real-world systems.

By the end of this lesson, you’ll be able to build:

✔ Login System
✔ Register User
✔ Secure Passwords (Hashing)
✔ JWT Tokens
✔ Protected Routes
✔ OAuth2 Password Flow
✔ Role-based access (Admin/User)

Let’s start. 🔥


🎯 What You Will Learn Today

✔ Authentication vs Authorization
✔ Password hashing (never store plain text)
✔ JWT token creation
✔ Secure login + token generation
✔ Protect APIs using OAuth2 scheme
✔ Role-based access example


🧠 1. Authentication vs Authorization (Very Simple)

  • Authentication → “Who are you?”
    (Login using username/password)
  • Authorization → “What can you access?”
    (Admin? Normal user? Can delete/update?)

FastAPI supports both using JWT & OAuth2.


🔐 2. Install Dependencies

pip install python-jose passlib[bcrypt]
  • python-jose → for JWT tokens
  • passlib + bcrypt → for password hashing

🧂 3. Password Hashing (NEVER store raw passwords)

from passlib.context import CryptContext

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

def hash_password(password: str):
    return pwd_context.hash(password)

def verify_password(plain, hashed):
    return pwd_context.verify(plain, hashed)

Test:

hashed = hash_password("admin123")
verify_password("admin123", hashed)  # True
verify_password("wrongpass", hashed) # False

🏗 4. User Model (Pydantic)

from pydantic import BaseModel

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

Database simulation:

db = {}  # {username: hashed_password}

🔐 5. JWT Token Setup

from datetime import datetime, timedelta
from jose import jwt

SECRET_KEY = "SUPER_SECRET_KEY_12345"
ALGORITHM = "HS256"

def create_token(data: dict):
    payload = data.copy()
    payload["exp"] = datetime.utcnow() + timedelta(minutes=30)
    return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)

🚪 6. Register Endpoint (Signup)

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.post("/register")
def register(user: User):
    if user.username in db:
        raise HTTPException(400, "User already exists")

    hashed_pw = hash_password(user.password)
    db[user.username] = hashed_pw

    return {"msg": "User registered"}

🔓 7. Login Endpoint → Issue JWT

class TokenResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"

@app.post("/login", response_model=TokenResponse)
def login(user: User):
    if user.username not in db:
        raise HTTPException(400, "Invalid username")

    if not verify_password(user.password, db[user.username]):
        raise HTTPException(400, "Invalid password")

    token = create_token({"sub": user.username})
    return TokenResponse(access_token=token)

Login returns:

{
  "access_token": "<JWT_TOKEN>",
  "token_type": "bearer"
}

🛡 8. Protect Routes Using OAuth2 Scheme

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")

🔑 9. Decode Token + Get Current User

def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        if username is None:
            raise HTTPException(401, "Invalid token")
        return username
    except:
        raise HTTPException(401, "Invalid token or expired")

🛠 10. Protected Route Example

from fastapi import Depends

@app.get("/profile")
def profile(user: str = Depends(get_current_user)):
    return {"logged_in_as": user}

Try accessing /profile without a token → 401 Unauthorized
Use Swagger:
Click Authorize → paste token → access allowed ✔


⭐ 11. Role-Based Access (Admin Only)

Add roles:

class User(BaseModel):
    username: str
    password: str
    role: str = "user"  # user/admin

Store role in DB:

db[user.username] = {"password": hashed_pw, "role": user.role}

Check role:

def is_admin(user: str = Depends(get_current_user)):
    if db[user]["role"] != "admin":
        raise HTTPException(403, "Admins only!")
    return user

Admin-only API:

@app.get("/admin")
def admin_dashboard(user: str = Depends(is_admin)):
    return {"msg": f"Welcome Admin {user}"}

🧪 12. Complete Authentication Flow

Step 1: Register a user

→ Store hashed password

Step 2: Login

→ Verify password
→ Create JWT token

Step 3: Protect routes

→ Validate token
→ Allow only authenticated users

Step 4: Role-based access

→ Allow admin-only endpoints

This is exactly what:

  • Banking apps
  • E-commerce
  • Admin dashboards
  • AI platforms
  • SaaS tools

use in production.


📌 Lesson 5 Summary

You learned how to build:

✔ Complete Login system
✔ Register endpoint
✔ Hashed passwords
✔ JWT tokens
✔ Protected API routes
✔ OAuth2 Password flow
✔ Role-based access

This is interview gold and industry standard.


🚀 Ready for Lesson 6 — Databases (SQL + NoSQL, SQLAlchemy, CRUD, relationships, async DB)?

Should I continue with Lesson 6 now?

Pages: 1 2 3 4 5 6 7 8 9 10 11