>_
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)