Ensure functions have docstrings for documentation
def verify_password(plain_password, hashed_password):
1from datetime import datetime, timedelta, timezone2from typing import Annotated34import jwt5from fastapi import Depends, FastAPI, HTTPException, Security, status6from fastapi.security import (7 OAuth2PasswordBearer,8 OAuth2PasswordRequestForm,9 SecurityScopes,10)11from jwt.exceptions import InvalidTokenError12from pwdlib import PasswordHash13from pydantic import BaseModel, ValidationError1415# to get a string like this run:16# openssl rand -hex 3217SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"18ALGORITHM = "HS256"19ACCESS_TOKEN_EXPIRE_MINUTES = 30202122fake_users_db = {23 "johndoe": {24 "username": "johndoe",25 "full_name": "John Doe",26 "email": "johndoe@example.com",27 "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc",28 "disabled": False,29 },30 "alice": {31 "username": "alice",32 "full_name": "Alice Chains",33 "email": "alicechains@example.com",34 "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE",35 "disabled": True,36 },37}383940class Token(BaseModel):41 access_token: str42 token_type: str434445class TokenData(BaseModel):46 username: str | None = None47 scopes: list[str] = []484950class User(BaseModel):51 username: str52 email: str | None = None53 full_name: str | None = None54 disabled: bool | None = None555657class UserInDB(User):58 hashed_password: str596061password_hash = PasswordHash.recommended()6263DUMMY_HASH = password_hash.hash("dummypassword")6465oauth2_scheme = OAuth2PasswordBearer(66 tokenUrl="token",67 scopes={"me": "Read information about the current user.", "items": "Read items."},68)6970app = FastAPI()717273def verify_password(plain_password, hashed_password):74 return password_hash.verify(plain_password, hashed_password)757677def get_password_hash(password):78 return password_hash.hash(password)798081def get_user(db, username: str):82 if username in db:83 user_dict = db[username]84 return UserInDB(**user_dict)858687def authenticate_user(fake_db, username: str, password: str):88 user = get_user(fake_db, username)89 if not user:90 verify_password(password, DUMMY_HASH)91 return False92 if not verify_password(password, user.hashed_password):93 return False94 return user959697def create_access_token(data: dict, expires_delta: timedelta | None = None):98 to_encode = data.copy()99 if expires_delta:100 expire = datetime.now(timezone.utc) + expires_delta101 else:102 expire = datetime.now(timezone.utc) + timedelta(minutes=15)103 to_encode.update({"exp": expire})104 encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)105 return encoded_jwt106107108async def get_current_user(109 security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]110):111 if security_scopes.scopes:112 authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'113 else:114 authenticate_value = "Bearer"115 credentials_exception = HTTPException(116 status_code=status.HTTP_401_UNAUTHORIZED,117 detail="Could not validate credentials",118 headers={"WWW-Authenticate": authenticate_value},119 )120 try:121 payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])122 username = payload.get("sub")123 if username is None:124 raise credentials_exception125 scope: str = payload.get("scope", "")126 token_scopes = scope.split(" ")127 token_data = TokenData(scopes=token_scopes, username=username)128 except (InvalidTokenError, ValidationError):129 raise credentials_exception130 user = get_user(fake_users_db, username=token_data.username)131 if user is None:132 raise credentials_exception133 for scope in security_scopes.scopes:134 if scope not in token_data.scopes:135 raise HTTPException(136 status_code=status.HTTP_401_UNAUTHORIZED,137 detail="Not enough permissions",138 headers={"WWW-Authenticate": authenticate_value},139 )140 return user141142143async def get_current_active_user(144 current_user: Annotated[User, Security(get_current_user, scopes=["me"])],145):146 if current_user.disabled:147 raise HTTPException(status_code=400, detail="Inactive user")148 return current_user149150151@app.post("/token")152async def login_for_access_token(153 form_data: Annotated[OAuth2PasswordRequestForm, Depends()],154) -> Token:155 user = authenticate_user(fake_users_db, form_data.username, form_data.password)156 if not user:157 raise HTTPException(status_code=400, detail="Incorrect username or password")158 access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)159 access_token = create_access_token(160 data={"sub": user.username, "scope": " ".join(form_data.scopes)},161 expires_delta=access_token_expires,162 )163 return Token(access_token=access_token, token_type="bearer")164165166@app.get("/users/me/")167async def read_users_me(168 current_user: Annotated[User, Depends(get_current_active_user)],169) -> User:170 return current_user171172173@app.get("/users/me/items/")174async def read_own_items(175 current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])],176):177 return [{"item_id": "Foo", "owner": current_user.username}]178179180@app.get("/status/")181async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):182 return {"status": "ok"}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.