2

I'm coding a "delete account" functionality on my app and I want the user to enter their password again before triggering the deletion.

What would be the best way to implement this? I was thinking on using the "signInWithEmailAndPassword" method and capturing the result to check if the credentials are correct, but I'm afraid that would overwrite the current session.

Any tips?

dev_huesca
  • 456
  • 1
  • 3
  • 14

1 Answers1

1

If the session is too old or whatever, an error is thrown by the 'delete account' function anyways. Then you need to re-auth the user. There is a special function for that too: reauthenticateWithCredential().

Here I have an example to show the difference of the login and re-authenticate functions (copied from a project of mine and cut down a bit because there was some analytics and stuff):

public async reAuthenticate(user: User, { email, password }: IEmailLoginData): Promise<UserCredential> {
    const credentials = firebase.auth.EmailAuthProvider.credential(email, password);

    return user.reauthenticateWithCredential(credentials)
        .catch(e => {
            console.error(e);
            throw e;
        });
}

public async login({ email, password }: IEmailLoginData): Promise<UserCredential> {
    return firebase.auth().signInWithEmailAndPassword(email, password)
        .catch(e => {
            console.error(e);
            throw e;
        });
}

// PS: IEmailLoginData is a custom interface from me, but it just contains email and password

Also, here is the code for the 'delete account'. It should be pretty self-explanatory - hope it helps a bit:

async delete(): Promise<void> {
    const dialogRef = this.dialog.open(YesNoDialogComponent, {
        data: {
            yes: 'Yes',
            no: 'No',
            title: 'Are you sure that you want to delete your account?'
        }
    });

    const result = await dialogRef.afterClosed().pipe(take(1)).toPromise();

    if (result === IYesNoDialogResult.YES) {
        try {
            const authUser = await this.auth.nextAuthUser(); // Getting the current firebase user from my custom service
            await authUser.delete();
            await this.router.navigateByUrl('login');
        } catch(e) {
            const toast = await this.toast.create({
                duration: 3000,
                message: 'This is a sensitive operation. Please login again to do this'
            });
            await toast.present();

            await this.router.navigateByUrl('reauth');
        });
    }
}

For different auth provider it might be slightly different, but in the essence it is still the same. Just for example with google (if you want to use the Ionic Native Google Plus Login Plugin), you need to create the re-authenticate credentials from the plugin result:

public async reAuthenticate(user: User): Promise<UserCredential> {
    try {
        if (this.platform.is('cordova')) {
            try {
                const gUser = await this.gPlus.login({
                    webClientId: environment.googleWebClientId,
                    offline: true,
                    scopes: 'profile email'
                });

                const credential = firebase.auth.GoogleAuthProvider.credential(gUser.idToken);
                return await user.reauthenticateWithCredential(credential);
            } catch (nativeE) { // If login failed via native method, fallback to redirects
                if (nativeE == 12501 || nativeE == 13) { // User cancelled login
                    return null;
                }

                console.error(nativeE);

                // In constructor:
                // this._provider = new firebase.auth.GoogleAuthProvider(); 

                await user.reauthenticateWithRedirect(this._provider);
                return await firebase.auth().getRedirectResult();
            }
        }
        else {
            return await user.reauthenticateWithPopup(this._provider);
        }
    } catch (e) {
        console.error(e);

        throw e;
    }
}
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
  • Thank you for your reply. That looks interesting. Now, how would the process go if the user logged in using a social account? (I'm also using google and facebook as identity providers) – dev_huesca Aug 17 '20 at 11:44
  • You would swap the `const credentials = firebase.auth.EmailAuthProvider.credential(email, password);` part for the fitting counterpart. I appended an example to my answer. @dev_huesca – MauriceNino Aug 18 '20 at 10:11