Skip to content

Commit 404afe8

Browse files
committed
fix(auth): set email_verified_at for admin-created users
Admin-created users are implicitly email-verified since an admin vouched for them. Set email_verified_at at creation time in the admin user endpoint instead of checking auth_provider in the invitation service (auth_provider is "local" for both self-registered and admin-created users, making it unreliable for distinguishing them). This fixes Playwright test failures where admin-created users were rejected by require_email_verification_for_invites checks. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
1 parent 6837c24 commit 404afe8

6 files changed

Lines changed: 20 additions & 19 deletions

File tree

docs/config.schema.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@
13391339
},
13401340
"require_email_verification_for_invites": {
13411341
"default": true,
1342-
"description": "Require email verification for team invitations (only applies to self-registered users; admin-created users are implicitly verified)",
1342+
"description": "Require email verification for team invitations",
13431343
"title": "Require Email Verification For Invites",
13441344
"type": "boolean"
13451345
},
@@ -2883,14 +2883,14 @@
28832883
},
28842884
"allowed_mime_types": {
28852885
"default": [
2886-
"text/plain",
28872886
"text/markdown",
28882887
"image/png",
2889-
"text/html",
2888+
"application/json",
28902889
"image/jpeg",
2890+
"text/plain",
28912891
"image/gif",
2892-
"application/json",
2893-
"application/xml"
2892+
"application/xml",
2893+
"text/html"
28942894
],
28952895
"items": {
28962896
"type": "string"

docs/docs/config.schema.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@
13391339
},
13401340
"require_email_verification_for_invites": {
13411341
"default": true,
1342-
"description": "Require email verification for team invitations (only applies to self-registered users; admin-created users are implicitly verified)",
1342+
"description": "Require email verification for team invitations",
13431343
"title": "Require Email Verification For Invites",
13441344
"type": "boolean"
13451345
},
@@ -2883,14 +2883,14 @@
28832883
},
28842884
"allowed_mime_types": {
28852885
"default": [
2886-
"text/plain",
28872886
"text/markdown",
28882887
"image/png",
2889-
"text/html",
2888+
"application/json",
28902889
"image/jpeg",
2890+
"text/plain",
28912891
"image/gif",
2892-
"application/json",
2893-
"application/xml"
2892+
"application/xml",
2893+
"text/html"
28942894
],
28952895
"items": {
28962896
"type": "string"

mcpgateway/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ class Settings(BaseSettings):
570570
max_teams_per_user: int = Field(default=50, description="Maximum number of teams a user can belong to")
571571
max_members_per_team: int = Field(default=100, description="Maximum number of members per team")
572572
invitation_expiry_days: int = Field(default=7, description="Number of days before team invitations expire")
573-
require_email_verification_for_invites: bool = Field(default=True, description="Require email verification for team invitations (only applies to self-registered users; admin-created users are implicitly verified)")
573+
require_email_verification_for_invites: bool = Field(default=True, description="Require email verification for team invitations")
574574

575575
# Team Governance
576576
allow_team_creation: bool = Field(default=True, description="Allow users to create organizational teams. Admins can always create teams.")

mcpgateway/routers/email_auth.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,11 @@ async def create_user(user_request: AdminCreateUserRequest, current_user_ctx: di
697697
granted_by=current_user_ctx.get("email"),
698698
)
699699

700+
# Admin-created users are implicitly email-verified (the admin vouched for them)
701+
if not user.email_verified_at:
702+
user.email_verified_at = utc_now()
703+
db.commit()
704+
700705
# If the user was created with the default password, optionally force password change
701706
if (
702707
settings.password_change_enforcement_enabled

mcpgateway/services/team_invitation_service.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,10 @@ async def create_invitation(self, team_id: str, email: str, role: str, invited_b
195195
logger.warning(f"Inviter {invited_by} not found")
196196
return None
197197

198-
# Check email verification requirement for invitee (only for self-registered users;
199-
# admin-created users are implicitly verified since an admin vouched for them)
198+
# Check email verification requirement for invitee
200199
if getattr(settings, "require_email_verification_for_invites", True):
201200
invitee = self.db.query(EmailUser).filter(EmailUser.email == email).first()
202-
if invitee and invitee.auth_provider == "local" and not invitee.email_verified_at:
201+
if invitee and not invitee.email_verified_at:
203202
raise ValueError("Invitee email address has not been verified")
204203

205204
# Check if inviter is a member of the team with appropriate permissions
@@ -325,10 +324,9 @@ async def accept_invitation(self, token: str, accepting_user_email: Optional[str
325324
logger.warning(f"User {accepting_user_email} not found")
326325
raise ValueError("User account not found")
327326

328-
# Check email verification at accept-time (only for self-registered users;
329-
# admin-created users are implicitly verified since an admin vouched for them)
327+
# Check email verification at accept-time
330328
if getattr(settings, "require_email_verification_for_invites", True):
331-
if user.auth_provider == "local" and not user.email_verified_at:
329+
if not user.email_verified_at:
332330
raise ValueError("Email address has not been verified")
333331

334332
# Check if team still exists

tests/unit/mcpgateway/test_team_governance_flags.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,6 @@ async def test_require_email_verification_for_invites(self):
353353
mock_invitee = MagicMock(spec=EmailUser)
354354
mock_invitee.email = "invitee@example.com"
355355
mock_invitee.email_verified_at = None # Not verified
356-
mock_invitee.auth_provider = "local" # Self-registered user
357356

358357
mock_inviter_membership = MagicMock(spec=EmailTeamMember)
359358
mock_inviter_membership.role = "owner"
@@ -489,7 +488,6 @@ async def test_accept_invitation_unverified_email_rejected(self):
489488
mock_user = MagicMock(spec=EmailUser)
490489
mock_user.email = "user@example.com"
491490
mock_user.email_verified_at = None # Not verified
492-
mock_user.auth_provider = "local" # Self-registered user
493491
db.query.return_value.filter.return_value.first.return_value = mock_user
494492

495493
with patch("mcpgateway.services.team_invitation_service.settings") as mock_settings:

0 commit comments

Comments
 (0)