docs_src/security/tutorial005_an_py310.py PYTHON 183 lines View on github.com → Search inside
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"}

Code quality findings 11

Ensure functions have docstrings for documentation
missing-docstring
def verify_password(plain_password, hashed_password):
Ensure functions have docstrings for documentation
missing-docstring
def get_password_hash(password):
Ensure functions have docstrings for documentation
missing-docstring
def get_user(db, username: str):
Ensure functions have docstrings for documentation
missing-docstring
def authenticate_user(fake_db, username: str, password: str):
Ensure functions have docstrings for documentation
missing-docstring
def create_access_token(data: dict, expires_delta: timedelta | None = None):
Ensure functions have docstrings for documentation
missing-docstring
async def get_current_user(
Ensure functions have docstrings for documentation
missing-docstring
async def get_current_active_user(
Ensure functions have docstrings for documentation
missing-docstring
async def login_for_access_token(
Ensure functions have docstrings for documentation
missing-docstring
async def read_users_me(
Ensure functions have docstrings for documentation
missing-docstring
async def read_own_items(
Ensure functions have docstrings for documentation
missing-docstring
async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.