diff --git a/CHANGELOG.md b/CHANGELOG.md index 8470f92c..88232c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to - ♿(frontend) improve contrast for selected options #863 - ♿️(frontend) announce copy state in invite dialog #877 - 📝(frontend) align close dialog label in rooms locale #878 +- 🩹(backend) use case-insensitive email matching in the external api #887 ## [1.3.0] - 2026-01-13 diff --git a/src/backend/core/external_api/viewsets.py b/src/backend/core/external_api/viewsets.py index a4ab2110..11b6fc6b 100644 --- a/src/backend/core/external_api/viewsets.py +++ b/src/backend/core/external_api/viewsets.py @@ -5,7 +5,7 @@ from logging import getLogger from django.conf import settings from django.contrib.auth.hashers import check_password -from django.core.exceptions import ValidationError +from django.core.exceptions import SuspiciousOperation, ValidationError from django.core.validators import validate_email import jwt @@ -93,7 +93,7 @@ class ApplicationViewSet(viewsets.GenericViewSet): ) try: - user = models.User.objects.get(email=email) + user = models.User.objects.get(email__iexact=email) except models.User.DoesNotExist as e: if ( settings.APPLICATION_ALLOW_USER_CREATION @@ -123,6 +123,10 @@ class ApplicationViewSet(viewsets.GenericViewSet): ) else: raise drf_exceptions.NotFound("User not found.") from e + except models.User.MultipleObjectsReturned as e: + raise SuspiciousOperation( + "Multiple user accounts share a common email." + ) from e now = datetime.now(timezone.utc) scope = " ".join(application.scopes or []) diff --git a/src/backend/core/tests/test_external_api_token.py b/src/backend/core/tests/test_external_api_token.py index 450dec9d..0701f384 100644 --- a/src/backend/core/tests/test_external_api_token.py +++ b/src/backend/core/tests/test_external_api_token.py @@ -22,7 +22,7 @@ pytestmark = pytest.mark.django_db def test_api_applications_generate_token_success(settings): """Valid credentials should return a JWT token.""" settings.APPLICATION_JWT_SECRET_KEY = "devKey" - user = UserFactory(email="user@example.com") + UserFactory(email="User.Family@example.com") application = ApplicationFactory( active=True, scopes=[ApplicationScope.ROOMS_LIST, ApplicationScope.ROOMS_CREATE], @@ -40,7 +40,7 @@ def test_api_applications_generate_token_success(settings): "client_id": application.client_id, "client_secret": plain_secret, "grant_type": "client_credentials", - "scope": user.email, + "scope": "user.family@example.com", }, format="json", )