Delete PFUser via CloudCode

Since Apple is requiring all apps that allow for account creation to also allow for account deletion in app, I am trying to update my app that uses Parse to follow guidelines. I have a CloudCode function set up:

    Parse.Cloud.define("deleteUserWithId", function(request, response) {
            var userId = request.params.userId;
            var query = new Parse.Query(Parse.User);
            
            query.get(userId).then(function(user) {
               
                return user.destroy();  { useMasterKey: true }
            }).then(function() {
                response.success(user);
            }, function(error) {
                response.error(error);
            });
        });

I then call it from the app as:

 PFUser *me = [[PFUser currentUser] fetch];
            NSString *objectID = me.username;
            [PFCloud callFunctionInBackground:@"deleteUserWithId"
                               withParameters:@{@"userId": objectID}
                                        block:^(NSString *success, NSError *error) {
                                            if (!error) {
                                                NSLog(@"Successful deletion");
                                            }
                                            else {
                                                NSLog(@"%@", error.description);
                                            }
                                        }];

The NSLog prints out “Successful deletion”, but in my Parse database, the user still shows up. In Cloud Code section I get this message:

UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag–unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)

There are a number of issues here, firstly:

Should be:

return user.destroy(); { useMasterKey: true }

Secondly:

The user variable isn’t available in this scope (as it’s declared in the previous .then callback)

Try this:

Parse.Cloud.define("deleteUserWithId", function(request, response) {
  var userId = request.params.userId;
  var query = new Parse.Query(Parse.User);
  query.get(userId).then(function(user) {
      return user.destroy({ useMasterKey: true });
  }).then(function() {
      response.success();
  }, function(error) {
      response.error(error);
  });
});

Although there is a key conceptual issue with this approach, as any user can delete another users’ account, which is a vulnerability. Using older Parse Server’s (which use success callbacks) are also very vulnerable.

A preferred approach would be:

Parse.Cloud.define("deleteUser", async function(request, response) {
  if (!request.user) {
    response.error('You are not logged in.');
    return;
  }
  try {
    await request.user.destroy({useMasterKey: true});
    response.success();
  } catch (e) {
    response.error(e);
  }
});

Which can be simplified even further on newer Parse Servers to:

Parse.Cloud.define("deleteUser", async ({user}) => {
  await user.destroy({useMasterKey: true});
}, {
  requireUser: true
});

It should be user.destroy({ useMasterKey: true });

But I’d highly recommend you validate which users can delete the other users. In the way this cloud code function is written, any user could use the function to delete any of the other users.

Also, providing you have the delete/destory CLP set up, you should be able to call [[PFUser currentUser] deleteInBackground...]

On the preferred approach, it is able to get the currently logged in user? Do I need to pass any parameters from the iOS app into it?

I tried the first approach you mentioned, and it still did not delete

is it possible to have a Parse-server feature that sends out a confirmation email with a link as a secondary step to confirm account deletion (much like confirming email address) ?

It would be great for account security purposes.

1 Like