FastAPI Authorization Verifying Permissions for PUT and DELETE

Learning objective: By the end of this lesson, students will be able to implement controller logic to verify data permissions based on the currently logged-in user.

In this lesson, we will add permission checks to the PUT and DELETE routes of our application. The goal is to ensure that only the user who created a specific tea can update or delete it. We will compare the user_id of the tea record with the id of the currently logged-in user. If the user IDs do not match, we will prevent the operation and return a 403 Forbidden error.

Verifying object permissions and error handling

In this step, we will add logic to check the user’s permissions before allowing updates or deletions of a tea record.

Implementing permission checks for update

To check if the user is allowed to update a tea record, we compare the user_id from the tea record with the id of the logged-in user. If they don’t match, we return a 403 Forbidden response:

# controllers/teas.py

@router.put("/teas/{tea_id}", response_model=TeaSchema)
def update_tea(tea_id: int, tea: TeaSchema, db: Session = Depends(get_db), current_user: UserModel = Depends(get_current_user)):
    db_tea = db.query(TeaModel).filter(TeaModel.id == tea_id).first()
    if not db_tea:
        raise HTTPException(status_code=404, detail="Tea not found")

    # Check if the current user is the creator of the tea
    if db_tea.user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Operation forbidden")

    tea_data = tea.dict(exclude_unset=True)
    for key, value in tea_data.items():
        setattr(db_tea, key, value)

    db.commit()
    db.refresh(db_tea)
    return db_tea

Implementing permission checks for delete

Similar to the update logic, we need to check that the logged-in user is the one who created the tea before allowing deletion:

# controllers/teas.py

@router.delete("/teas/{tea_id}")
def delete_tea(tea_id: int, db: Session = Depends(get_db), current_user: UserModel = Depends(get_current_user)):
    db_tea = db.query(TeaModel).filter(TeaModel.id == tea_id).first()
    if not db_tea:
        raise HTTPException(status_code=404, detail="Tea not found")

    # Check if the current user is the creator of the tea
    if db_tea.user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Operation forbidden")

    db.delete(db_tea)
    db.commit()
    return {"message": f"Tea with ID {tea_id} has been deleted"}

Testing final code

Now that we’ve added final permission checks, it’s important to test that the logic works as expected.

Test unauthorized access

Test authorized access

Congratulations! You’ve now secured your routes and implemented object-level permissioning.

Enjoy your work and make your own cup of tea!