YouTip LogoYouTip

Fastapi Blog Jwt Auth

User System โ€” Registration, Login, JWT Authentication |

\\n\\n

In this chapter, you will learn FastAPI's JWT authentication scheme and understand the difference between it and Django/Flask Session authentication.

\\n\\n
\\n\\n

JWT vs Session Authentication

\\n\\n

Django and Flask use Session authentication: the server stores the user state, and only the Session ID is stored in the Cookie.

\\n\\n

FastAPI recommends JWT authentication: after logging in, the user obtains a Token, and subsequent requests can be authenticated by carrying the Token.

\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
FeatureSession (Django/Flask)JWT (FastAPI)
Storage LocationServer-side (Memory/Database)Client-side (Cookie/LocalStorage)
ScalabilityServer needs to share SessionStateless, natively supports distributed systems
Applicable ScenariosServer-side rendered websitesAPI + SPA / Mobile
Expiration ControlCan be invalidated by the server at any timeValid throughout the Token's lifetime
\\n\\n
\\n\\n

Install Dependencies

(venv) $ pip install passlib python-jose python-multipart\\n
\\n\\n
    \\n
  • passlib๏ผšPassword Hashing (Equivalent to werkzeug.security๏ผ‰
  • \\n
  • python-jose๏ผšJWT generation and verification
  • \\n
  • python-multipart๏ผšHandle form submission (OAuth2 login form)
  • \\n
\\n\\n
\\n\\n

Define User Model

\\n\\n

Example

# File Path: models.py Add\\n\\nfrom passlib.context import CryptContext\\n\\npwd_context = CryptContext(schemes=, deprecated="auto")\\n\\nclass User(Base):\\n\\n __tablename__ ="users"\\n\\nid= Column(Integer, primary_key=True, index=True)\\n\\n username = Column(String(50), unique=True, nullable=False)\\n\\nemail= Column(String(120), unique=True, nullable=False)\\n\\n hashed_password = Column(String(256), nullable=False)\\n\\ndef set_password(self, password: str):\\n\\n"""Hash Password"""\\n\\nself.hashed_password= pwd_context.hash(password)\\n\\ndef verify_password(self, password: str) ->bool:\\n\\n"""Verify Password"""\\n\\nreturn pwd_context.verify(password,self.hashed_password)\\n
\\n\\n

Generate and Run Migrations:

\\n\\n
(venv) $ alembic revision --autogenerate -m "Add User model"(venv) $ alembic upgrade head\\n
\\n\\n
\\n\\n

JWT Utility Functions

\\n\\n

Examples

\\n\\n
# File path๏ผšauth.py๏ผˆCreate New File)\\n\\nfrom datetime import datetime, timedelta\\n\\nfrom jose import JWTError, jwt\\n\\nfrom passlib.context import CryptContext\\n\\nfrom fastapi import Depends, HTTPException, status\\n\\nfrom fastapi.security import OAuth2PasswordBearer\\n\\n# Secret key๏ผˆproduction environment (read from environment variables)๏ผ‰\\n\\n SECRET_KEY ="your-secret-key-change-in-production"\\n\\n ALGORITHM ="HS256"\\n\\n ACCESS_TOKEN_EXPIRE_MINUTES =60 * 24# Token validity period๏ผš24 hours\\n\\n# OAuth2PasswordBearer tells FastAPI๏ผšFromrequest header Authorization: Bearer <token> inextract JWT\\n\\n oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")\\n\\ndef create_access_token(data: dict) ->str:\\n\\n"""Generate JWT Token"""\\n\\n to_encode = data.copy()\\n\\n expire =datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)\\n\\n to_encode.update({"exp": expire})\\n\\nreturn jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)\\n\\ndef decode_access_token(token: str) ->dict | None:\\n\\n"""verify and decode JWT Token"""\\n\\ntry:\\n\\n payload = jwt.decode(token, SECRET_KEY, algorithms=)\\n\\nreturn payload\\n\\nexcept JWTError:\\n\\nreturn None\\n
\\n\\n
\\n\\n

Register routes

\\n\\n

Examples

\\n\\n
# File Path: routers/users.py\\n\\nfrom fastapi import APIRouter, Depends, HTTPException, Request, Form\\n\\nfrom fastapi.templating import Jinja2Templates\\n\\nfrom sqlalchemy.orm import Session\\n\\nfrom database import get_db\\n\\nfrom models import User\\n\\nfrom schemas import UserCreate, UserResponse\\n\\nfrom auth import create_access_token\\n\\nrouter = APIRouter(prefix="/users", tags=)\\n\\n templates = Jinja2Templates(directory="templates")\\n\\n@router.post("/register", response_model=UserResponse)\\n\\ndef register(\\n\\n username: str= Form(...),\\n\\nemail: str= Form(...),\\n\\n password: str= Form(...),\\n\\n db: Session = Depends(get_db)\\n\\n):\\n\\n"""User Registration"""\\n\\n# check if username and email already exist\\n\\nif db.query(User).filter(User.username== username).first():\\n\\nraise HTTPException(status_code=400, detail="Username already used")\\n\\nif db.query(User).filter(User.email==email).first():\\n\\nraise HTTPException(status_code=400, detail="Email Already Registered")\\n\\nuser= User(username=username,email=email)\\n\\nuser.set_password(password)\\n\\n db.add(user)\\n\\n db.commit()\\n\\n db.refresh(user)\\n\\nreturn user\\n
\\n\\n
\\n\\n

Login Route (Issue JWT)

\\n\\n

Examples

\\n\\n
# File Path: routers/users.py Append\\n\\nfrom fastapi.security import OAuth2PasswordRequestForm\\n\\nfrom auth import create_access_token\\n\\n@router.post("/token")\\n\\ndef login_for_access_token(\\n\\n form_data: OAuth2PasswordRequestForm = Depends(),\\n\\n db: Session = Depends(get_db)\\n\\n):\\n\\n"""\\n\\n Login and Get Token\\n\\n use OAuth2PasswordRequestForm๏ผšfield names are username and password๏ผˆform format๏ผ‰\\n\\n """\\n\\nuser= db.query(User).filter(User.username== form_data.username).first()\\n\\nif not user or not user.verify_password(form_data.password):\\n\\nraise HTTPException(\\n\\n status_code=401,\\n\\n detail="Userusername or password error",\\n\\n headers={"WWW-Authenticate": "Bearer"}\\n\\n)\\n\\n# Issue JWT: Include Only user_id (Do Not Include Sensitive Information)\\n\\n access_token = create_access_token(data={"sub": str(user.id)})\\n\\nreturn{"access_token": access_token,"token_type": "bearer"}\\n
\\n\\n
\\n

JWT Token in subis the standard subject field, storing the user identifier. The token itself is not encrypted (it is only Base64 encoded), so you must never include sensitive information like passwords in it. If you need encryption, use JWE instead of JWT.

\\n
\\n\\n
\\n\\n

Protecting Routes with JWT

\\n\\n

Example

# Dependency Function to Get Current User\\n\\nfrom auth import oauth2_scheme, decode_access_token\\n\\ndef get_current_user(\\n\\ntoken: str= Depends(oauth2_scheme),\\n\\n db: Session = Depends(get_db)\\n\\n):\\n\\n"""From JWT Token inparse currentUser"""\\n\\n payload = decode_access_token(token)\\n\\nif payload is None:\\n\\nraise HTTPException(status_code=401, detail="Token Invalid or Expired")\\n\\nuser_id = payload.get("sub")\\n\\nuser= db.query(User).filter(User.id==int(user_id)).first()\\n\\nif user is None:\\n\\nraise HTTPException(status_code=401, detail="User does not exist")\\n\\nreturn user\\n\\n# inject into routes that require login\\n\\n@router.get("/me", response_model=UserResponse)\\n\\ndef read_current_user(current_user: User = Depends(get_current_user)):\\n\\n"""Get currentUserinformation๏ผˆrequires login๏ผ‰"""\\n\\nreturn current_user\\n

For SSR pages, JWTs are typically stored in cookies (rather than the Authorization header), and the token is extracted from the cookie in template routes for verification.

\\n\\n
\\n\\n

Chapter Summary

\\n\\n

In this chapter, you implemented JWT authentication in FastAPI:passlib Hash Passwordใ€python-jose Issue and Verify JWT,OAuth2PasswordBearer extract token,DependsImplement authentication dependency injection.

\\n\\n

Unlike Django/Flask's Session authentication, JWT is a stateless solution that is better suited for front-end and back-end separation scenarios.

โ† Fastapi Blog DeployVue3 Blog Composable โ†’