Skip to content

AuthData validation is incorrectly triggered on unlink/no-op updates, breaking multi-provider flows #9999

Closed

Description

@SNtGog

New Issue Checklist


Issue Description

Parse Server validates all existing authData providers during user updates, even when a provider is unchanged and not part of the update.

For code-based auth adapters (requiring code), this causes valid multi-provider update flows to fail, because Parse attempts to revalidate providers that were not modified and therefore do not include a code in the update payload.

This makes partial authData updates non-functional and breaks multi-provider user accounts.


Steps to reproduce

Using any code-based auth adapter (example below uses a gpgames-like adapter that requires code):

it('should handle multiple providers: add one while another remains unchanged', async () => {
  const user = await Parse.User.logInWith('gpgames', {
    authData: { id: MOCK_USER_ID, code: 'C1' },
  });
  const sessionToken = user.getSessionToken();
  await user.fetch({ sessionToken });

  const current = user.get('authData') || {};
  user.set('authData', {
    ...current,
    instagram: { id: 'I1', code: 'ic1' },
    // gpgames is NOT modified
  });
  await user.save(null, { sessionToken });

  const reloaded = await new Parse.Query(Parse.User).get(user.id, {
    useMasterKey: true,
  });

  const authData = reloaded.get('authData') || {};
  expect(authData.instagram && authData.instagram.id).toBe('I1');
  expect(authData.gpgames && authData.gpgames.id).toBe(MOCK_USER_ID);
});

Actual Outcome

user.save() fails with an adapter validation error, for example:

Error: gpgames code is required.

This shows that Parse attempts to validate the existing gpgames provider even though it was not modified and no code was provided in the update.


Expected Outcome

  • The new provider (instagram) is added successfully.
  • The existing provider (gpgames) remains unchanged.
  • Adapter validation is triggered only for providers whose authData was actually modified.

Environment

Server

  • Parse Server version: 9.1.0
  • Operating system: Debian 12
  • Local or remote host: Remote (self-hosted)

Database

  • System: MongoDB
  • Database version: 8.1
  • Local or remote host: MongoDB Atlas

Logs

Error: gpgames code is required.
    at validateAuthData (...)

Activity

  1. parse-github-assistant commented on Dec 30, 2025

    @parse-github-assistant

    🚀 Thanks for opening this issue!

    ℹ️ You can help us to fix this issue faster by opening a pull request with a failing test. See our Contribution Guide for how to make a pull request, or read our New Contributor's Guide if this is your first time contributing.

  2. pcg92 commented on Jan 26, 2026

    @pcg92

    We're experiencing a related issue with the Flutter SDK (parse_server_sdk_flutter).

    When a user deletes their account, the Flutter app calls user.unset("authData") which stores {"authData": {"__op": "Delete"}} in the local sembast storage.

    If the user later tries to re-register with Google/Apple auth, the SDK sends:

    {
      "authData": {
        "google": { "id": "...", "access_token": "...", "id_token": "..." },
        "__op": "Delete"
      }
    }

    Parse Server then iterates over all keys in authData and treats __op as an auth provider, resulting in:

    Error 252: "This authentication method is unsupported." provider: "__op"
    

    This started happening after upgrading from parse_server_sdk_flutter 8.0.0 to 10.6.2. The unset() operation has always stored the __op locally, but something changed in how the SDK serializes/merges local data with new auth data.

    Workaround: We added an Express middleware to strip __op from authData before it reaches Parse Server:

    app.use('/parse', express.json(), (req, res, next) => {
      if (req.body?.authData?.__op) {
        delete req.body.authData.__op;
      }
      next();
    });

    This confirms the root cause is the same: Parse Server validates all keys in authData as providers, even when they shouldn't be treated as such.

  3. mtrezza commented on Jan 27, 2026

    @mtrezza
    Member

    Could you please try out #10025 and see whether it fixes the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions