>_
EngineeringNotes
← Back to FastAPI & Python
Module 04

Authentication & Security

JWT, OAuth2, Password Hashing, and Role-Based Access Control (RBAC).

01

Authentication vs Authorization

These terms are often used interchangeably, but they serve completely different purposes in a secure system.

ConceptMeaningAnalogy
Authentication"Who are you?"Identity Card / Passport
Authorization"What can you access?"Premises Access Card / Keys

👉 Example: Logging in is Authentication. Once logged in, being allowed to access the /admin dashboard is Authorization.

🔑 Common Authentication Methods

Session-based
Traditional stateful auth
Token-based
Modern stateless APIs
OAuth2
Third-party & complex flows
JWT
Compact & Scalable (Standard)
02

JWT (JSON Web Token)

A compact, URL-safe means of representing claims to be transferred between two parties. It is the most common authentication method in modern FastAPI applications.

Part 1
Header

Specifies algorithm (e.g., HS256) and token type.

Part 2
Payload

Contains data claims (User ID, Role, Expire time).

Part 3
Signature

The hashed content used to verify token integrity.

Why JWT?

✔
Stateless
No server-side storage required.
✔
Scalable
Perfect for horizontal scaling.
✔
Microservices
Identity carries across services.

📥 Installation

Terminal
bash
pip install python-jose[cryptography] passlib[bcrypt]
03

Secure Password Hashing

🛡️

The Golden Rule

Never store plain text passwords in your database. Always hash them using robust algorithms like Bcrypt.

❌ Wrong Way
Plain Text
python
password = "123456"
# Storing as-is in DB
✅ Correct Way
Hashed
python
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"])
hash = pwd_context.hash("123456")
Security Utils
python
def hash_password(password: str):
    return pwd_context.hash(password)

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

OAuth2 & JWT Implementation

1. OAuth2 Password Flow

FastAPI uses OAuth2PasswordBearer as a dependency to extract the token from the Header.

Auth Setup
python
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

2. Login & Token Creation

Converting validated credentials into a secure JWT.

Auth Logic
python
from jose import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-complex-secret"
ALGORITHM = "HS256"

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=30)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # 1. Fetch user from DB\n    # 2. Verify password\n    # 3. Create token\n    token = create_access_token({"sub": user.id})
    return {"access_token": token, "token_type": "bearer"}
05

Protected Routes

The get_current_user dependency decodes the JWT and verifies the signature on every request to a protected endpoint.

Dependency Injection
python
def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: str = payload.get("sub")
        if user_id is None:
            raise HTTPException(status_code=401)
        return user_id
    except Exception:
        raise HTTPException(status_code=401, detail="Invalid token")

@app.get("/users/me")
def read_me(current_user_id: str = Depends(get_current_user)):
    return {"user_id": current_user_id}
06

Full Auth Flow (Step-by-Step)

1
📝 Register
User registers → password is automatically hashed.
2
🔑 Login
User logs in → system verifies hash & issues JWT.
3
💾 Storage
Client stores token (LocalStorage / Cookies).
4
📡 Request
Client sends token in Header: Authorization: Bearer <token>
5
🛡️ Verify
Server decodes & verifies signature → Access granted.
07

RBAC: Role-Based Access Control

Permission Checkers

Implementing authorization by checking user roles decoded from the JWT or fetched from DB.

RBAC Handler
python
def require_role(allowed_role: str):
    def checker(user_role: str = Depends(get_user_role_from_db)):
        if user_role != allowed_role:
            raise HTTPException(status_code=403, detail="Forbidden")
        return True
    return checker

@app.get("/admin/metrics", dependencies=[Depends(require_role("admin"))])
def get_metrics():
    return {"data": "Secure admin metrics"}
08

Production Security Checklist

✅ Best Practices
  • 🚀 Use HTTPS only
  • 🔑 Store SECRET_KEY in .env
  • ⏳ Set short token expiration
  • 🔄 Implement Refresh Tokens
❌ Vulnerabilities
  • 💣 Exposing passwords in logs
  • 💣 Hardcoded secrets in code
  • 💣 No rate limiting
  • 💣 Insufficient role validation
09

Refresh Tokens (Advanced Concept)

⏳ Access Token

Short lifespan (e.g., 15-30 mins). Used for every API request to minimize damage if stolen.

🔄 Refresh Token

Long lifespan (e.g., 7-30 days). Used only to generate new access tokens without requiring re-login.

10

Security Middleware

Middlewares allow you to inject security headers globally for every HTTP request.

Middleware Setup
python
@app.middleware("http")
async def add_security_headers(request, call_next):
    response = await call_next(request)
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    return response
11

Interview Preparation

🧠 Theory Questions

What is JWT?▼
A compact token-based mechanism for securely transmitting user identity between client and server.
Why use JWT over sessions?▼
Statelessness (no server storage needed), high scalability, and native support for microservices.
Explain Authentication vs Authorization.▼
Authentication verifies 'Who are you?' (Login). Authorization verifies 'What can you access?' (Permissions).
What is Hashing?▼
Converting data into an irreversible fixed-length string to store sensitive info like passwords securely.
What is RBAC?▼
Role-Based Access Control - assigning permissions based on assigned user roles.
What is a Bearer Token?▼
An opaque token sent in the 'Authorization' header as 'Bearer <token>' for identifying the sender.
What is OAuth2?▼
An industry-standard protocol for authorization that allows applications to share data securely without sharing passwords.
What happens if token expires?▼
The server rejects the request (401). The user must re-authenticate or use a refresh token to get a new access token.

💻 Coding Challenges

Q1: Hash Device Password
Hashing Logic
python
from passlib.context import CryptContext
context = CryptContext(schemes=["bcrypt"])
hashed = context.hash("mypassword")
Q2: Create JWT Token
Token Generation
python
from jose import jwt

SECRET = "supersecret"
ALGO = "HS256"

def create_token(user_id: str):
    return jwt.encode({"sub": user_id}, SECRET, algorithm=ALGO)
Q3: Protect Route
Route Guard
python
@app.get("/secure")
def secure(user = Depends(get_current_user)):
    return {"msg": "Secure"}
Q4: Role-based route
RBAC Guard
python
@app.get("/admin")
def admin(user = Depends(require_role("admin"))):
    return {"msg": "Admin"}
12

🧩 Bonus: Security in ML APIs

💡

For ML APIs, security isn't just about logs; it's about Model Misuse Prevention and Sensitive Inference Protection. Ensure model parameters or raw training data are never exposed in prediction outputs.

Secure Inference
python
@app.post("/predict")
def predict(data: InputData, user = Depends(get_current_user)):
    # Only authorized users can trigger inference
    return model.predict(data)