π Get User detail's and Change password endpoint
In this session we will:
Create a new route called
users.pyCreate two API endpoints:
β Get logged-in user information
β Change user password (with verification)
This is extremely common in real-world backend systems.
π Step 1 β Create users.py
Inside routers create users.py
routers/users.pyπ¦ Step 2 β Copy Base Dependencies
From todos.py, copy the shared dependency setup.
But we will correct and clean it properly.
routes/users.py
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from fastapi import APIRouter, Depends, HTTPException
from starlette import status
from passlib.context import CryptContext
from models import Users
from database import SessionLocal
from .auth import get_current_user
router = APIRouter(
prefix="/user",
tags=["user"]
)π Database Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
user_dependency = Annotated[dict, Depends(get_current_user)]π Step 3 β Password Hashing Context
We need the same hashing logic as routes/auth.py here.
bcrypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

π€ Step 4 β Endpoint 1: Get Current User Info
We want:
Only authenticated users
Return the user record from the database
@router.get("/", status_code=status.HTTP_200_OK)
async def get_user(
user: user_dependency,
db: db_dependency
):
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication Failed"
)
user_model = db.query(Users).filter(
Users.id == user.get("id")
).first()
return user_modelπ§ Whatβs Happening?
Creates a GET endpoint that returns 200 OK.
Uses
user_dependencyto get the authenticated user from the JWT token.Uses
db_dependencyto access the database session.Checks if the user is authenticated; otherwise raises 401 Unauthorized.
Queries the Users table using the user ID from the token.
Returns the user record from the database.
π§© Step 5 β Register Router in main.py
Inside main.py:
from routers import auth, todos, admin, usersThen include it:
app.include_router(auth.router)
app.include_router(todos.router)
app.include_router(admin.router)
app.include_router(users.router)π Run the Application
uvicorn main:app --reloadYou should now see:
/userAuthorize β Try it β It returns your user info.
π Step 6 β Create Password Change Model
We need the user to send:
current password
new password
Create a Pydantic model:
class UserVerification(BaseModel):
password: str
new_password: str = Field(min_length=6)
π Step 7 β Change Password Endpoint
Now we create a PUT endpoint.
@router.put("/password", status_code=status.HTTP_204_NO_CONTENT)
async def change_password(
user_verification: UserVerification,
user: user_dependency,
db: db_dependency
):
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication Failed"
)
user_model = db.query(Users).filter(
Users.id == user.get("id")
).first()
# Verify current password
if not bcrypt_context.verify(
user_verification.password,
user_model.hashed_password
):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Error while changing password"
)
# Hash and update new password
user_model.hashed_password = bcrypt_context.hash(
user_verification.new_password
)
db.add(user_model)
db.commit()
π How This Works
Step 1
User sends:
{
"password": "current_password",
"new_password": "new_secure_password"
}
Step 2
We verify:
bcrypt_context.verify()
Step 3
If correct β hash new password
bcrypt_context.hash()
Step 4
Save to database
from typing import Annotated
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from fastapi import APIRouter, Depends, HTTPException
from starlette import status
from passlib.context import CryptContext
from models import Users
from database import SessionLocal
from .auth import get_current_user
router = APIRouter(
prefix="/user",
tags=["user"]
)
bcrypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
user_dependency = Annotated[dict, Depends(get_current_user)]
class UserVerification(BaseModel):
password: str
new_password: str = Field(min_length=6)
@router.get("/", status_code=status.HTTP_200_OK)
async def get_user(
user: user_dependency,
db: db_dependency
):
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication Failed"
)
user_model = db.query(Users).filter(
Users.id == user.get("id")
).first()
return user_model
@router.put("/password", status_code=status.HTTP_204_NO_CONTENT)
async def change_password(
user_verification: UserVerification,
user: user_dependency,
db: db_dependency
):
if user is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication Failed"
)
user_model = db.query(Users).filter(
Users.id == user.get("id")
).first()
# Verify current password
if not bcrypt_context.verify(
user_verification.password,
user_model.hashed_password
):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Error while changing password"
)
# Hash and update new password
user_model.hashed_password = bcrypt_context.hash(
user_verification.new_password
)
db.add(user_model)
db.commit()π§ͺ Testing Scenarios
Changing the password from test1234 to test123 and trying to login again