Covered topics: Installation, Configuration, Password and Token Utilities, Token Endpoint.
Installation
uv add "pyjwt[crypto]" "pwdlib[argon2]" python-multipart
Configuration
import os
from datetime import datetime, timedelta, timezone
import jwt
from jwt.exceptions import InvalidTokenError
from pwdlib import PasswordHash
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
SECRET_KEY = os.environ["JWT_SECRET_KEY"]
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
password_hash = PasswordHash.recommended()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/token")
Password and Token Utilities
def hash_password(password: str) -> str:
return password_hash.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return password_hash.verify(plain, hashed)
def create_access_token(data: dict, expires_delta: timedelta | None = None) -> str:
to_encode = data.copy()
expire = datetime.now(timezone.utc) + (expires_delta or timedelta(minutes=15))
to_encode["exp"] = expire
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
Token Endpoint
@router.post("/token")
def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_session),
):
user = db.exec(select(User).where(User.username == form_data.username)).first()
if not user or not verify_password(form_data.password, user.hashed_password):
raise HTTPException(status_code=401, detail="Invalid credentials")
access_token = create_access_token(
data={"sub": str(user.id)},
expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES),
)
return {"access_token": access_token, "token_type": "bearer"}
Current User Dependency
def get_current_user(
token: str = Depends(oauth2_scheme),
db: Session = Depends(get_session),
) -> User:
credentials_exception = HTTPException(status_code=401, detail="Invalid token")
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id = payload.get("sub")
if user_id is None:
raise credentials_exception
except InvalidTokenError:
raise credentials_exception
user = db.get(User, int(user_id))
if user is None:
raise credentials_exception
return user
@app.get("/tasks/")
def list_tasks(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_session),
):
statement = select(Task).where(Task.owner_id == current_user.id)
return db.exec(statement).all()
๐ฌ Comments (0)
No comments yet
Be the first to share your opinion about this article!