Cognito User Pool – Sign in, Register and Sign Up user process

    AWS Cognito User pools are for mobile and web app developers who want to handle user registration and sign-in directly in their apps. User Pool allows you to create and maintain a user directory, add sign-up and sign-in to your mobile app or web application and scale to hundreds of millions of users very simple, secure, and low-cost.

    You can use user pools to add user registration and sign-in features to your apps. Users can register with or sign in to an app using an email address, phone number, or a user name. You can also create custom registration fields and store that metadata in your user directory. You can verify email addresses and phone numbers, recover passwords, and enable multi-factor authentication (MFA) with just a few lines of code.

    Amazon Cognito user pools are PCI- and HIPAA-compliant.

    You can get started with user pools by using the AWS Management Console, the AWS Command Line Interface, or the APIs provided in one of our SDKs.

    Using Node.js we want to see steps of user registration and how tokens are exchanged with AWS Cognito User pool. Next, we will use generated token for making secure API call.

    Create Cognito User Pool

    Navigate to ‘AWS Cognito’ -> ‘Manage your User Pools’ and choose ‘Create a User pool’:

    • Add user pool name
    • Choose Step through settings
    • Leave first section “How do you want your end users to sign in?” by default. Users will sign in only by providing username.
    • From standard attributes choose email, address and name.
    • Leave next screen by default:
    • Next screen will ask you to create Role for sending SMS messages. But, because in this scenario we will send only e-mail, do not create the role and just click Next:
    • On next screen you can customize SMS and e-mail messages:
    • Leave by default several screens that asks for tags, devices, actions and ‘Register Application’. Create your pool.
    • After the user pool is created you will get “Pool Id”. You can find this number under pool’s General setting -> Pool Id. Value is in format <region_unique code>.
    • From “General settings” menu navigate to “App clients” and register one. Number for “App client id” that is generated after registration will be include in all Web or Mobile apps that are going to use this pool. Of course, you can register different App clients for different applications.

     

    Create API

    Navigate to AWS API Gateway and create one API that will have Authorizer. Authorizers enable you to control access to your APIs using Amazon Cognito User Pools or a Lambda function.

    Choose your User Pool and for Token Source add Authorization. That will be the request header parameter that will hold user JWT Token ID value.

    For target API backend you can add Lambda function that will decode JWT Token ID in order to get user information.

    Code snippet for Lambda function can be the following one:

    var jwt_decode = require('jwt-decode');
    
    exports.handler = (event, context, callback) => {
      var decoded = jwt_decode(event.params.header.Authorization);
      callback(null, decoded);
    };

    Sign-up user via custom application

    In Node.js for user authentication we are using following libraries:

    https://github.com/aws/amazon-cognito-identity-js

    https://github.com/aws/amazon-cognito-js

    Following snippet defines Cognito User Pool and Application that are used for new user registration:

    const poolData = {
        UserPoolId: '<region_unique number',
        ClientId: 'application id'
    };
    const userPool = new AWS.CognitoIdentityServiceProvider.CognitoUserPool(poolData);

    In order to register, user must provide all required attributes, username and password. That information is used in sign up process. Following snippet populates attributes list and sign up user:

    var attributeList = [];
    var attributeName = new AWS.CognitoIdentityServiceProvider.CognitoUserAttribute('name','John Smith');
    var attributeAddress =new AWS.CognitoIdentityServiceProvider.CognitoUserAttribute('address','Sunshine street 123');
    var attributeEmail =new AWS.CognitoIdentityServiceProvider.CognitoUserAttribute('email','john.smith@mail.com');
    attributeList.push(attributeName);
    attributeList.push(attributeAddress);
    attributeList.push(attributeEmail);
    
    var cognitoUser;
    userPool.signUp('johns', 'P@ssw0rd', attributeList, null, function(err, result){
        if (err) {
            console.log(err);
            return;
        }
    
        cognitoUser = result.user;
        console.log('user name is ' + cognitoUser.getUsername());
    });

    Remember, email must be valid email address in order to receive verification code and finish the sign-up process. Now, if you navigate to Cognito Users and Group, under Users you will see new user with username ‘johns’ and user status ‘Enabled/UNCONFIRMED’ and ‘email_verified = false’.

    After several minutes user will get Verification code within an e-mail message:

    “Your verification code is 123456.”

    Let’s verify the user.

    Verify user via verification code

    Following snippet defines Cognito User Pool and Application that are used for user verification. Additionally, we define Cognito user by providing the username.

    const poolData = {
        UserPoolId: '<region_unique number',
        ClientId: 'application id'
    };
    const userPool = new AWS.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
    
    var userData = {
        Username: 'johns',
        Pool: userPool
    };
    
    var cognitoUser = new AWS.CognitoIdentityServiceProvider.CognitoUser(userData);

    When user has the Verification code, it is passed to Cognito in order to confirm the registration:

    cognitoUser.confirmRegistration('096146', true, function(err, result) {
        if (err) {
            console.log(err);
            return;
        }
    
        console.log('call result: ' + result);
    });

    After SUCCESS message, you can navigate to AWS Cognito User Pool and see the user status as CONFIRMED and email_verified = true. Now, user can sign-in using Cognito and access the API.

    Sign-in

    User is verified and enabled to use his/her credentials in order to authenticate. From user credentials Cognito generates JWT Token ID, Access token and Refresh token.

    Here is Sign in code snippet:

    const poolData = {
        UserPoolId: '<region_unique number',
        ClientId: 'application id'
    };
    
    const userPool = new AWS.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
    
    var authenticationData = {
        Username: 'johns',
        Password: 'P@ssw0rd'
    };
    
    var userData = {
        Username: 'johns',
        Pool: userPool
    };
    
    var authenticationDetails = new AWS.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
    var cognitoUser = new AWS.CognitoIdentityServiceProvider.CognitoUser(userData);
    cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: function(result) {
            console.log('Access Token:' + JSON.stringify(jwt_decode(result.getAccessToken().getJwtToken())));
            console.log('Id Token + ' + JSON.stringify(jwt_decode(result.getIdToken().getJwtToken())));
            console.log('Refresh Token + ' + JSON.stringify(result.getRefreshToken().getToken()));
        },
    
        onFailure: function(err) {
            console.error(err);
        }
    
    });

    Now, from the App we can make call to the API. The API Cognito Authorizer authenticate and authorize this user to access Lambda in the background. At Request Header we can also send Token ID so at Lambda level we can have info about user who has accessed the resource, his attribute values etc.

    Just decode the JWT token and information is there:

    var decoded = jwt_decode(event.params.header.Authorization);
    
    {"sub":"<GUID>","cognito:groups":["AppUser"],"email_verified":true,"address":{"formatted":"Sunshine street 123"},"iss":"https://cognito-idp.<region>.amazonaws.com/<user pool id>","cognito:username":"johns","aud":"<number>","token_use":"id","auth_time":1509103712,"name":"John Smith","exp":1509107312,"iat":1509103712,"email":" john.smith@mail.com"}

    If you want to learn more how to add custom access permissions, read following article: Amazon Cognito and API Gateway AWS IAM Authorization

    Conclusion

    Cognito User Pool allows quick and easy way to register and authenticate your users and provide secured access to your API’s. This is only a glace of the capabilities that Cognito provides.

    Using Node.js libraries you can manage user’s information like update attributes and password change.

    More info can be found on: http://docs.aws.amazon.com/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-javascript-examples.html