From c1054c800f84c9801b97cf0dd1ba9481f706f3f4 Mon Sep 17 00:00:00 2001 From: Thiago Victoriano Date: Fri, 24 Apr 2026 14:48:53 -0300 Subject: [PATCH 1/2] Improve token validation in password reset flow --- backend/app/utils.py | 5 ++++- backend/tests/api/routes/test_login.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/backend/app/utils.py b/backend/app/utils.py index 29fcfc1471..9c14c82049 100644 --- a/backend/app/utils.py +++ b/backend/app/utils.py @@ -118,6 +118,9 @@ def verify_password_reset_token(token: str) -> str | None: decoded_token = jwt.decode( token, settings.SECRET_KEY, algorithms=[security.ALGORITHM] ) - return str(decoded_token["sub"]) + subject = decoded_token.get("sub") + if not isinstance(subject, str) or not subject: + return None + return subject except InvalidTokenError: return None diff --git a/backend/tests/api/routes/test_login.py b/backend/tests/api/routes/test_login.py index 96677a25f6..6d6d76dbff 100644 --- a/backend/tests/api/routes/test_login.py +++ b/backend/tests/api/routes/test_login.py @@ -1,9 +1,11 @@ from unittest.mock import patch from fastapi.testclient import TestClient +import jwt from pwdlib.hashers.bcrypt import BcryptHasher from sqlmodel import Session +from app.core import security from app.core.config import settings from app.core.security import get_password_hash, verify_password from app.crud import create_user @@ -126,6 +128,27 @@ def test_reset_password_invalid_token( assert response["detail"] == "Invalid token" +def test_reset_password_token_without_subject_claim( + client: TestClient, superuser_token_headers: dict[str, str] +) -> None: + token_without_sub = jwt.encode( + {"nbf": 0, "exp": 4102444800}, + settings.SECRET_KEY, + algorithm=security.ALGORITHM, + ) + data = {"new_password": "changethis", "token": token_without_sub} + r = client.post( + f"{settings.API_V1_STR}/reset-password/", + headers=superuser_token_headers, + json=data, + ) + response = r.json() + + assert "detail" in response + assert r.status_code == 400 + assert response["detail"] == "Invalid token" + + def test_login_with_bcrypt_password_upgrades_to_argon2( client: TestClient, db: Session ) -> None: From 08625ddf44153d91a8ae8cd70131e4a0cbf0dc8b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:50:53 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format=20and=20update?= =?UTF-8?q?=20with=20pre-commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/tests/api/routes/test_login.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tests/api/routes/test_login.py b/backend/tests/api/routes/test_login.py index 6d6d76dbff..a12a621328 100644 --- a/backend/tests/api/routes/test_login.py +++ b/backend/tests/api/routes/test_login.py @@ -1,7 +1,7 @@ from unittest.mock import patch -from fastapi.testclient import TestClient import jwt +from fastapi.testclient import TestClient from pwdlib.hashers.bcrypt import BcryptHasher from sqlmodel import Session