How to check if a user exists and has authData?

I try to check if a user exists with this function but it always returns undefined. What is wrong?
I want to know if a user exists to prevent my oauth integration from creating new accounts on each login.

Parse.Cloud.define("userExists", async (req) => {
  const { email } = req.params;

  return await new Parse.Query(Parse.User)
    .equalTo("email", email)
    .exists("authData")
    .first({ useMasterKey: true });
});

And this is how I call it

    const { email, id, id_token, access_token } = authData;
    const exists = await Parse.Cloud.run("userExists", { email });

I’m aware that querying by email is disabled outside cloud environment. That’s why I created a cloud function for that purpose and use masterKey in it. But why isn’t it working?

authData appears to be of those magic data types that can’t be included in a query. I ended up setting a custom flag and checking based on it.

if user try re-register with same email, should get this error

Account already exists for this email address.

if you want to query by email you can do it for ex : where={“email":"[email protected]”}

Returning an object that has been queried with a masterKey is a potential vulnerability as it removes the access control of a User, and exposes any protectedFields. It is much safer to ensure that a cloud function returns a message or bool, such as:

Parse.Cloud.define("userExists", async (req) => {
  const { email } = req.params;
  const user = await new Parse.Query(Parse.User)
    .equalTo("email", email)
    .exists("authData")
    .first({ useMasterKey: true });
  return !!user;
});

Although an attacker could easily brute force this endpoint to sniff out users’ emails. (Side note, you can use rateLimit on Parse Server version 6)

You might be able to query auth data with .exists("_auth_data_${authName}"). What auth method are you using? I normally do something like:

await Parse.User.logInWith("apple", {
  authData: {
   token,
   id,
   email,
  }
});

Then in beforeSave:

const appleAuth = object.get("authData")?.apple;
const email = appleAuth?.email;
if (email) {
  object.set("email", email);
  delete appleAuth.email;
  object.set("authData", { apple: appleAuth });
}
1 Like

Thank you for help. This was for google auth.

I need the userExists function because I need to create some tables the first time a user registers.

This means that I need to skip doing this on subsequent logins.

That’s why even though your solution is sleeker it doesn’t fit my purpose. But I’ve refactored my function to return a boolean only per your suggestion…

Parse.Cloud.define("userExists", async (req) => {
  const { email, auth } = req.params;

  const result = await new Parse.Query(Parse.User)
    .equalTo("email", email)
    .equalTo("auth", auth) // the custom auth flag e.g. "g" for google
    .first({ useMasterKey: true });

  return result !== undefined;
});