Allowing Users to Delete Their Own AWS Cognito Accounts With Amplify and the AWS JS SDK v3

January 02, 2021 0 Comments technology

Introduction

We're using AWS Amplify with AWS Cognito and the Hosted UI to handle Authentication for Cork Hounds. To provide users with the ability to delete their own accounts (along with any/all data that we manage on their behalf), we must interface with Cognito and the Hosted UI. Providing the ability for users to manage their data continues to rise in importance to maintain compliance with new data privacy/ownership laws, including "The California Consumer Privacy Act of 2018 (CCPA)" and "The European Union General Data Protection Regulation of 2016 (GDPR)".

Once a user deletes their account, it is important to sign them out globally. However, at the time of this writing, there is an issue that interferes with signout of the Hosted UI when using just Amplify by itself. I'll provide a work around that's supported by AWS using the new aws-sdk-js-v3 library. Let's dive in!

Overview

The AWS Amplify Auth.currentAuthenticatedUser returns a CognitoUser with a deleteUser method, which allows you to do the following:

Auth.currentAuthenticatedUser({
    bypassCache: true  // Optional, By default is false. 
}).then((user) => {
    user.deleteUser((error, data) => {
    if (error) {
        throw error;
    }
    
    // Delete all user data in your system
    
    // Log the user out 
    Auth.signOut({ global: true });
    });
}).catch(err => console.log(err));

However, Auth.signOut() doesn't sign the user out of the Hosted UI after using the deleteUser method.This issue is highlighted in ticket 3187 on the aws-amplify github repo. This is not fixed as of AWS Amplify version 3.3.13. While that ticket provides an unsupported workaround, I wanted a solution that would work into the future.

Using the AWS JS SDK seemed to make the most sense. On the GitHub readme for Amplify 3.x.x, it says they've removed the AWS SDK version 2.x in favor of version 3. The AWS JS SDK Version 3 is designed to be modular, to help with reducing package sizes / tree shaking. You can see a list of the modules on AWS' JavaScript SDK documentation.

Assumptions & Getting Started

I am going to assume you are already using AWS Amplify, AWS Cognito and the Hosted UI, and that you are looking for a way to (1) let users delete their own Cognito accounts, and then (2) sign the user out globally. You should be using a 3.x version of AWS Amplify.

To get started, you'll want to install the client-cognito-identity-provider from the aws js sdk v3:

npm i @aws-sdk/client-cognito-identity-provider --save

I believe you'll also need to enable the aws.cognito.signin.user.admin OAuth scope. This can be found via the AWS console for Cognito under User Pools > App Integration > App Client Settings > Allowed OAuth Scopes. According to the Cognito App Client Settings:

The aws.cognito.signin.user.admin scope grants access to Amazon Cognito User Pool API operations that require access tokens, such as UpdateUserAttributes and VerifyUserAttribute.

Code

We want to leverage the CognitoIdentityProvider to perform the deleteUser function. By deleting the user outside of Amplify, it allows the Auth.signOut() function to operate as intended. So lets import the necessary components:


import Auth from '@aws-amplify/auth';
import {CognitoIdentityProvider} from '@aws-sdk/client-cognito-identity-provider';

If you wanted to leverage other properties/functions from the client-cognito-identity-provider library, you could simply import everything:

import * as AWS from '@aws-sdk/client-cognito-identity-provider';

Assuming you imported the CognitoIdentityProvider, you can use it with amplify as shown below.


// We call currentAuthenticatedUser to get a current AccessToken
Auth.currentAuthenticatedUser({
        bypassCache: true  // Optional, By default is false. 
    }).then((user) => {
        
       // Create a new CognitoIdentityProvider object for your Cognito User Pool Region
       const cognitoIdentityProvider = new CognitoIdentityProvider({region: 'us-west-2'});
       
       // Create the required request parameter
       var params = {
           AccessToken: user.signInUserSession.accessToken.jwtToken
       };
       
       // Call the deleteUser function using a callback function
       cognitoIdentityProvider.deleteUser(params, function(err, data) {
            if (err) {
              console.log(err);
            }
          
            // Your code to delete user data
         
            // Sign the user out
            Auth.signOut({ global: true });
         
       });

    }).catch(err => console.log(err));

When Auth.signOut({ global: true}) is called, it will trigger a signout from the Hosted UI, and return the user to your signout URL. As noted in the AWS Amplify documentation for Signup, Signin, and Signout:

By doing this, you are revoking all the auth tokens (id token, access token and refresh token) which means the user is signed out from all the devices Note: although the tokens are revoked, the AWS credentials will remain valid until they expire (which by default is 1 hour).

Conclusion

Hopefully you found this helpful/useful. Would love your feedback!

Jeremy Glesner
Jeremy Glesner
Virginia Website
Jeremy is a technology executive in the Washington DC area, and the lead engineer for Cork Hounds. Posting stories related to the technological underpinnings of Cork Hounds.

You've successfully subscribed to The Cork Hounds Blog
Great! Next, complete checkout for full access to The Cork Hounds Blog
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.