Skip to content

fix: API token 422 error on GET /auth/email/me#2728

Merged
crivetimihai merged 3 commits intomainfrom
fix/2700-auth-email-me-validation-error
Feb 7, 2026
Merged

fix: API token 422 error on GET /auth/email/me#2728
crivetimihai merged 3 commits intomainfrom
fix/2700-auth-email-me-validation-error

Conversation

@shoummu1
Copy link
Copy Markdown
Collaborator

@shoummu1 shoummu1 commented Feb 6, 2026

🐛 Bug-fix PR

📌 Summary

Fixed 422 validation error when calling GET /auth/email/me with API tokens. The EmailUserResponse schema requires auth_provider and password_change_required fields, but some code paths in auth.py were creating EmailUser objects without setting these fields, causing Pydantic validation to fail with a 422 error.

🔗 Related Issue

Closes #2700

🐞 Root Cause

The EmailUserResponse schema (mcpgateway/schemas.py:5318-5319) requires auth_provider and password_change_required as mandatory fields. However, 5 locations in mcpgateway/auth.py that instantiate EmailUser objects were not setting these fields:

  • _get_user_by_email_sync() (line 375)
  • _user_from_cached_dict() (line 475)
  • Plugin authentication path (line 617)
  • Platform admin bootstrap - batched query path (line 869)
  • Platform admin bootstrap - fallback path (line 1007)

When get_current_user_profile() called EmailUserResponse.from_email_user(), it attempted to access these missing fields, triggering Pydantic validation errors.

💡 Fix Description

Implementation Changes:

  • Updated all 5 EmailUser() instantiation points in auth.py to include:
    • auth_provider (defaults to "local", "api_token" for API tokens)
    • password_change_required (defaults to False)
  • Updated _get_auth_context_batched_sync() to include both fields in cached user dicts (line 436)

Test Changes:

  • Updated test_api_token_authentication_success() to use realistic mocks with all required fields
  • Added test_emailuser_response_serialization_with_api_token() regression test to verify serialization works without validation errors

All changes maintain backward compatibility and follow existing patterns in the codebase.

🧪 Verification

Check Command Status
Lint suite make lint
Unit tests make test
Coverage ≥ 90 % make coverage
Manual regression no longer fails GET /auth/email/me with API token returns 200

Tests added:

  • tests/unit/mcpgateway/routers/test_email_auth_router.py::test_emailuser_response_serialization_with_api_token
  • Updated: tests/unit/mcpgateway/test_auth.py::TestGetCurrentUser::test_api_token_authentication_success

📐 MCP Compliance (if relevant)

  • Matches current MCP spec (N/A - internal auth API)
  • No breaking change to MCP clients (N/A - internal auth API)

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • No secrets/credentials committed
  • Regression test added to prevent recurrence
  • All existing tests pass

@shoummu1 shoummu1 force-pushed the fix/2700-auth-email-me-validation-error branch from 9daa3d1 to 280ae41 Compare February 6, 2026 09:42
@shoummu1 shoummu1 marked this pull request as ready for review February 6, 2026 10:36
@crivetimihai crivetimihai self-assigned this Feb 6, 2026
Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
@crivetimihai crivetimihai force-pushed the fix/2700-auth-email-me-validation-error branch from 0edcc46 to 076c2e6 Compare February 7, 2026 11:24
@crivetimihai
Copy link
Copy Markdown
Member

Review

Rebased cleanly onto main. All 60 auth tests pass.

Root cause confirmed: EmailUserResponse.auth_provider is a required Pydantic field (no default), but detached EmailUser objects created manually in auth.py didn't set it — SQLAlchemy default= only applies at flush/commit, not at Python construction time. Same issue for password_change_required.

Fix is correct and complete. All 5 EmailUser() instantiation sites in auth.py are covered:

  • _get_user_by_email_sync — reads actual DB values ✅
  • _get_auth_context_batched_sync — reads actual DB values ✅
  • _user_from_cached_dict — safe .get() defaults ✅
  • Plugin auth path — safe .get() defaults ✅
  • Platform admin bootstrap (x2) — hardcoded "local" / False

No other EmailUser() instantiation in production code is missing these fields (email_auth_service.py already sets auth_provider explicitly).

No security or performance concerns. Default values are safe/restrictive. No changes to auth logic.

Minor note: test_api_token_authentication_success sets auth_provider="api_token" on the mock, but in production the DB user would have auth_provider="local" (registration method) — the current auth method is tracked in request.state.auth_method instead. Non-blocking, just a readability observation.

LGTM.

@crivetimihai crivetimihai merged commit 18abdde into main Feb 7, 2026
51 checks passed
@crivetimihai crivetimihai deleted the fix/2700-auth-email-me-validation-error branch February 7, 2026 11:32
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
* fix(auth): add missing fields to EmailUser instantiations

Signed-off-by: Shoumi <shoumimukherjee@gmail.com>

* add regression test for API token /me endpoint serialization

Signed-off-by: Shoumi <shoumimukherjee@gmail.com>

* test fixes

Signed-off-by: Shoumi <shoumimukherjee@gmail.com>

---------

Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: API Call - /auth/email/me - 422 Error is shown

2 participants