fix(storefront-auth): forgot/reset password accept JSON body, not query
Some checks failed
Some checks failed
POST /api/v1/storefront/auth/forgot-password and .../reset-password were
both declared with bare `email: str` / `reset_token: str, new_password: str`
parameters. FastAPI treats unannotated str params as query parameters, so
the frontend's JSON body was ignored and the endpoint 422'd with
"missing query parameter 'email'". The docstrings on both endpoints
already said "Request Body" — intent was clear, implementation drifted.
Add two new Pydantic body schemas in tenancy/schemas/auth.py:
PasswordResetRequest { email: str } (forgot)
PasswordResetConfirm { reset_token: str, new_password: str } (reset)
Re-export from tenancy/schemas/__init__.py, import in
customers/routes/api/storefront.py, and switch both endpoint signatures
to take `body: <Schema>`. Internal usage reads body.email / body.reset_token
/ body.new_password.
Surfaced during Test 5 when user clicked "forgot password" on the customer
storefront login page to set a password for the first time after a
self-enrollment flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,8 @@ from app.modules.messaging.services.email_service import (
|
||||
from app.modules.tenancy.exceptions import StoreNotFoundException
|
||||
from app.modules.tenancy.schemas.auth import (
|
||||
LogoutResponse,
|
||||
PasswordResetConfirm,
|
||||
PasswordResetRequest,
|
||||
PasswordResetRequestResponse,
|
||||
PasswordResetResponse,
|
||||
UserLogin,
|
||||
@@ -230,7 +232,9 @@ def customer_logout(request: Request, response: Response):
|
||||
|
||||
|
||||
@router.post("/auth/forgot-password", response_model=PasswordResetRequestResponse) # public
|
||||
def forgot_password(request: Request, email: str, db: Session = Depends(get_db)):
|
||||
def forgot_password(
|
||||
request: Request, body: PasswordResetRequest, db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Request password reset for customer.
|
||||
|
||||
@@ -245,6 +249,7 @@ def forgot_password(request: Request, email: str, db: Session = Depends(get_db))
|
||||
if not store:
|
||||
raise StoreNotFoundException("context", identifier_type="subdomain")
|
||||
|
||||
email = body.email
|
||||
logger.debug(
|
||||
f"[CUSTOMER_STOREFRONT] forgot_password for store {store.subdomain}",
|
||||
extra={
|
||||
@@ -299,7 +304,7 @@ def forgot_password(request: Request, email: str, db: Session = Depends(get_db))
|
||||
|
||||
@router.post("/auth/reset-password", response_model=PasswordResetResponse) # public
|
||||
def reset_password(
|
||||
request: Request, reset_token: str, new_password: str, db: Session = Depends(get_db)
|
||||
request: Request, body: PasswordResetConfirm, db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Reset customer password using reset token.
|
||||
@@ -323,8 +328,8 @@ def reset_password(
|
||||
customer = customer_service.validate_and_reset_password(
|
||||
db=db,
|
||||
store_id=store.id,
|
||||
reset_token=reset_token,
|
||||
new_password=new_password,
|
||||
reset_token=body.reset_token,
|
||||
new_password=body.new_password,
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
@@ -53,6 +53,8 @@ from app.modules.tenancy.schemas.auth import (
|
||||
LoginResponse,
|
||||
LogoutResponse,
|
||||
OwnedMerchantSummary,
|
||||
PasswordResetConfirm,
|
||||
PasswordResetRequest,
|
||||
PasswordResetRequestResponse,
|
||||
PasswordResetResponse,
|
||||
PlatformSelectResponse,
|
||||
@@ -153,6 +155,8 @@ __all__ = [
|
||||
"LoginResponse",
|
||||
"LogoutResponse",
|
||||
"OwnedMerchantSummary",
|
||||
"PasswordResetConfirm",
|
||||
"PasswordResetRequest",
|
||||
"PasswordResetRequestResponse",
|
||||
"PasswordResetResponse",
|
||||
"PlatformSelectResponse",
|
||||
|
||||
@@ -183,12 +183,25 @@ class LogoutResponse(BaseModel):
|
||||
message: str
|
||||
|
||||
|
||||
class PasswordResetRequest(BaseModel):
|
||||
"""Schema for password reset request body (customer / storefront forgot-password)."""
|
||||
|
||||
email: str
|
||||
|
||||
|
||||
class PasswordResetRequestResponse(BaseModel):
|
||||
"""Schema for password reset request response."""
|
||||
|
||||
message: str
|
||||
|
||||
|
||||
class PasswordResetConfirm(BaseModel):
|
||||
"""Schema for password reset confirm body (customer / storefront reset-password)."""
|
||||
|
||||
reset_token: str
|
||||
new_password: str
|
||||
|
||||
|
||||
class PasswordResetResponse(BaseModel):
|
||||
"""Schema for password reset response."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user