Tag: JavaScript


Push Notifications with Ionic and Amazon Pinpoint

Engaging your customers through communication channels such as push notifications is important for mobile app success. AWS services such as AWS Mobile Hub and Amazon Pinpoint enable you to do this in a scalable and cost effective manner. When using these services with development tooling like Ionic Framework you can rapidly develop modern applications to build your business.

Ionic recently announced that they are sunsetting their Push and Auth services. We recently launched an Ionic Starter Project and posted a tutorial for adding sign-up and sign-in to an Ionic project to help customers evaluate AWS as an alternative for migration. In this post, we cover how to add push notifications to your Ionic project with Amazon Pinpoint.

In this tutorial, we show how to add push notifications with Google Cloud Messaging (GCM). A similar procedure can be followed for Apple Push Notification service (APNs) which you can find on the Apple Developer website.

(more…)

User Sign-in and Sign-up for Ionic Mobile Apps with Amazon Cognito

This post was written by Brice Pelle, AWS Technical Account Manager.

In our previous blog post, we described how to secure and deploy RESTful interfaces for the Ionic Framework using the AWS SDK for JavaScript and AWS Mobile Hub, with support for authenticated and unauthenticated users. This allows guest users to use your app, with limited privileges, without having an account. When users are ready, they can sign up for an account and sign in. This gives them access to more features in the app. Sign-up and sign-in functionality in a mobile app can be difficult to implement securely and challenging to manage.

In this post, we take a deeper look at how AWS Mobile Hub along with Amazon Cognito provide a foundation for user sign-up and sign-in. We describe how these services integrate in your Ionic Framework mobile app. We use the same sample app introduced in the previous post to showcase the implementation. Refer to the previous blog post for instructions on how to deploy backend resources with Mobile Hub and how to launch the app.

(more…)

Deploy and Secure REST-based Mobile Apps with AWS Mobile Hub

This post was written by Brice Pelle, AWS Technical Account Manager.

RESTful APIs are used today to power many mobile apps. Using RESTful interfaces allows developers to decouple the frontend application from the backend systems and provides standard interoperability between the two components. Controlling access to resources can be hard to set up. This usually requires addressing authentication and authorization concerns.

In this article, I am going to look at how AWS Mobile Hub helps build a serverless mobile backend that exposes REST interfaces, and uses Amazon Cognito to help developers integrate authentication and authorization into an Ionic v2 app. I will be using a sample app, to demonstrate the implementation. The app is a simple task management app that allows access to authenticated and unauthenticated users.  I will cover authentication in the second part of this blog.

(more…)

Building fine-grained authorization using Amazon Cognito User Pools groups

This post was authored by Leo Drakopoulos, AWS Solutions Architect.

User authentication and authorization can be challenging when building web and mobile apps. The challenges include handling user data and passwords, token-based authentication, managing fine-grained permissions, scalability, federation, and more.

In this post, we show how to integrate authentication and authorization into an Angular web app by using AWS services. You can use Amazon Cognito to control permissions for different user groups in your app. This ensures that users have appropriate access to backend resources, determined by the group they belong to.

(more…)

Deploying an EmberJS mobile web application with Mobile Hub

This post was authored by Michael Labieniec, AWS Sr. Solutions Architect.

Ember.js is a popular open source JavaScript framework for developing rich, dynamic web applications. It supports dependancy injection model and has been a is a stable contender in the JavaScript community. Ember.js also ships with its own CLI which supports building, testing, and deploying your applications. The Ember CLI supports installing plugins and the bundling of those plugins within your application, it has a built in web server to serve your application locally.

AWS Mobile Hub is an AWS service that guides you through feature selection and configuration, it automatically provisions the AWS services required. Mobile Hub generates working code that helps you integrate the AWS SDK for JavaScript with your application in minutes. When using Mobile Hub to develop JavaScript-based applications, JavaScript configuration files as well as a sample web application are generated for you, and placed in your Amazon S3 bucket. These configuration files can then be copied directly to your application environment for use. The files can be continuously updated when your AWS environment changes via Mobile Hub. This is useful for developing JavaScript web applications because your AWS configuration can be dynamically updated by Mobile Hub and your application can immediately realize and support those updates when hosted in Amazon S3.

(more…)

Integrate the AWS SDK for JavaScript into a React App

In our last blog post, I showed how to create a React app using the create-react-app tool provided by Facebook, and then deploy the app to a content delivery network driven by AWS Mobile Hub, Amazon S3, and Amazon CloudFront. This enables you to produce dynamic single page applications (SPAs) and serve them to a global audience.

Very few web apps are static web sites.  Ideally, you also deploy a serverless backend that includes identity, database, storage, and custom APIs that provide the dynamic data for your SPA. AWS provides this kind of serverless backend. You can compose this backend by using the AWS Mobile Hub console. You still need to integrate the AWS SDK for JavaScript into your SPA. In this post, we walk through that integration.

Add the AWS SDK for JavaScript to your project

The SDK is distributed via the npm package manager. To install the SDK into your project, use the following command:

npm install –save aws-sdk

This downloads the SDK and adds an entry into the package.json file so that the SDK is downloaded automatically when it is needed. In addition, any dependencies for the SDK are downloaded and included in your project.

Download the AWS configuration for your project

In the last article, we showed you how to create an AWS Mobile Hub project and turn on the Hosting and Streaming service. This also generates two files in the Amazon S3 bucket that is created:

  • aws-config.js is used by browser sessions to configure the SDK.
  • aws-exports.js is used by SPA applications that are packed (by Webpack, Browserify, or similar tools) to configure the SDK.

You need the aws-exports.js file for the React app. You can download this file from the Amazon S3 bucket using either the AWS Mobile Hub console or the AWS CLI. To download via the CLI, use the following:

aws s3 cp s3://bucket/aws-exports.js ./src/aws-exports.js

From the AWS Mobile Hub console:

  1. Sign in to the AWS Mobile Hub console.
  2. Choose your project.
  3. Choose Hosting and Streaming.
  4. Click Download aws-exports.js file.

You can (and should) do this before every build. I have included the following in my package.json:

{
	"scripts": {
		"prebuild": "aws s3 cp s3://${S3BUCKET}/aws-exports.js ./src/aws-exports.js",
		"build": "react-scripts build",
		"deploy": "aws s3 cp ./build s3://${S3BUCKET}/ --recursive",
		"start": "react-scripts start",
		"test": "react-scripts test –env=jsdom",
		"eject": "react-scripts eject"
	},
	…
}

Set the S3BUCKET environment variable and build the React app as follows:

# For MacOS or Linux
export S3BUCKET=reacttestapp-hosting-mobilehub-1234567890
# For Windows cmd
# set S3BUCKET=reacttestapp-hosting-mobilehub-1234567890
# For Windows PowerShell
# $env:S3BUCKET="reacttestapp-hosting-mobilehub-1234567890"

# Now run the build
npm run build

Integrate the SDK into your app

In each SPA, there is an entry point. The entry point for all apps created by create-react-app is the src/App.js file. The create-react-app tool uses ES2015 modules.  This means we can use the import keyword to bring in the aws-exports.js file:

/*
 * Import the SDK and Project Configuration
 */
import AWS from 'aws-sdk';
import awsmobile from './aws-exports';

/*
 * Configure the SDK to use anonymous identity 
 */
AWS.config.update({
  region: awsmobile.aws_cognito_region,
  credentials: new AWS.CognitoIdentityCredentials({
    IdentityPoolId: awsmobile.aws_cognito_identity_pool_id
  })
});

In this snippet, we import both the SDK and the configuration of the backend, and then automatically create identity credentials for Amazon Cognito based on the configuration. We can also use this to instantiate an Amazon DynamoDB connection or call an Amazon API Gateway REST endpoint using the SDK.

What’s in the aws-exports.js

The aws-exports.js file is a standard JavaScript file that is maintained by AWS Mobile Hub on your behalf. It changes when you add, remove, or edit features within AWS Mobile Hub. An example from one of my apps is below:

// WARNING: DO NOT EDIT. This file is Auto-Generated by AWS Mobile Hub. It will be overwritten.

// Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved.
// Code generated by AWS Mobile Hub. Amazon gives unlimited permission to
// copy, distribute and modify it.

// AWS Mobile Hub Project Constants
const awsmobile = {
aws_app_analytics : 'enable',
aws_cognito_identity_pool_id : 'us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
aws_cognito_region : 'us-east-1',
aws_content_delivery : 'enable',
aws_content_delivery_bucket : 'XXXXXX-hosting-mobilehub-1234567890',
aws_content_delivery_bucket_region : 'us-east-1',
aws_content_delivery_cloudfront : 'enable',
aws_content_delivery_cloudfront_domain : 'XXXXXXXXXXX.cloudfront.net',
aws_mobile_analytics_app_id : 'XXXXXXXXXXXXXXXXXXXXXXX',
aws_project_id : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX ',
aws_project_name : 'XXXXXX’,
aws_project_region : 'us-east-1',
aws_resource_name_prefix : 'XXXXXX-mobilehub-1234567890’,
}

export default awsmobile;
var AWS = require('aws-sdk');
AWS.config.region = awsmobile.aws_project_region;
AWS.config.update({customUserAgent: 'MobileHub v0.1'});

This project has the following enabled:

  • Analytics (from the Messaging and Analytics feature)
  • Hosting and Streaming

You can see the appropriate IDs are available through constants that are then exported as a module. You should never edit this file directly. Instead, change the features within your AWS Mobile Hub project and then copy the file to your source code control again.

Best Practices

We consider the following best practices for integrating the SDK:

  1. Always use the latest version of the SDK.
  2. Add the src/aws-exports.js file to your .gitignore (or similar) file. Do not check this file into your source code repository.
  3. Copy the aws-exports.js file from your AWS Mobile Hub project during the build phase of your app.

Now that you know how to integrate the SDK into your app, you can start using the AWS SDK for JavaScript to access your AWS services. In future articles, we will explore adding AWS service access to your React app. Until then, please see the AWS SDK for JavaScript Developer Guide for more details.

Enhanced JavaScript development with AWS Mobile Hub

by Richard Threlkeld | on | Permalink | Comments |  Share

Introduction

As the JavaScript ecosystem grows, we continue to invest to help customers build mobile and hybrid apps. Today, we released a feature in AWS Mobile Hub called Hosting and Streaming. This feature automates deployment of mobile websites in both test and production scenarios using Amazon S3 and Amazon CloudFront. It also helps developers streamline their configuration workflow with standard configuration files and SDKs.

With this new capability JavaScript developers can launch preconfigured AWS architectures or build them from the Mobile Hub project interface. With a single click, developers can create a global website with central configuration settings and pre-downloaded SDKs.

Overview

Go to the Mobile Hub console and choose Create a new Project, enable some features such as User Sign-in, NoSQL Database or Cloud Logic. Alternatively you can import an existing project.

Select Hosting and Streaming to view the launch page for your hosted Mobile Web application.

 

 

 

Choose one of the Launch buttons to run the sample app, either directly from Amazon S3 hosting or from an Amazon CloudFront deployment. The sample is a JavaScript application that makes a sample call to Amazon Cognito demonstrating how to get an identity and credentials.

Choose Manage files. This takes you to the S3 bucket that AWS Mobile Hub configured with your resources. The resources include the webpage you just launched and the AWS SDK for JavaScript. In addition this directory contains two important files:

  • aws-config.js
  • aws-exports.js

These files contain the AWS references for your mobile web or hybrid apps. You can use these references in your JavaScript app when communicating with AWS services. The sample app shows how to use the aws-config.js to make an unauthenticated call to Amazon Cognito. If you configure the User Sign-in feature to require sign-in (this is recommended), then Mobile Hub configures AWS Identity and Access Management policies so that only users with valid authentication can access the other features (like Amazon DynamoDB or Amazon API Gateway) in your project. A good example of this is in the AWS Ionic Starter project launched last month.

The aws-exports.js file is a new ECMAScript2015 compliant file we introduced to help you write applications that follow this standard.

Walkthrough: aws-exports.js with Babel and NodeJS

To get started with aws-exports.js, here is a walkthrough that creates a project which compiles using Babel. The walkthrough then shows how to use the AWS SDK for JavaScript to use these capabilities.

Babel is a JavaScript compiler for newer JavaScript language features such as Import and Export statements that are standardized in ES2015. You can read more about Babel here.

To get started first ensure that you have NodeJS and NPM installed.

Next create a project directory with a source and destination location for Babel to read from and write files to. Then, initialize your project:


$mkdir awsmobile
$cd awsmobile
$mkdir dist
$mkdir src
$npm init

Initialize the directory with defaults. Now, install the Babel prerequisites and create an entry point for your code along with the AWS SDK for JavaScript:


$npm install --save-dev babel-cli babel-preset-env aws-sdk
$touch .babelrc
$touch ./src/awstest.js

Edit the .babelrc file with the following code:

{ "presets": ["env"] }

Notice that the awstest.js file is in the ./src directory. Edit the awstest.js file using a text editor with the following code:



'use strict';
import { awsmobile } from './aws-exports';
console.log(awsmobile);

Place aws-exports.js from S3 bucket generated by Mobile Hub into the ./src directory. When awstest.js is compiled by Babel, the output will be in the ./dist directory. You can execute this with the following commands:

$./node_modules/.bin/babel ./src --experimental --source-maps-inline -d ./dist
$node dist/awstest.js

If everything worked correctly, your configuration settings for communicating with AWS are printed to the screen.

Downloading files from Amazon S3 with the AWS SDK for JavaScript and aws-exports.js

Now that you’ve got the basics of the build process how can you use these settings? Mobile Hub handles all the heavy lifting of configuring AWS Cloud resources. Suppose you want to download a file from the S3 bucket that was created. The following code shows an example of using the aws-exports.js settings file with a simple app that performs a GetObject operation and writes the index.html file as mobilehub.html to your local disk. Modify your ./src/awstest.js with the following code:


'use strict';

import { awsmobile } from './aws-exports';
import AWS from 'aws-sdk';

//Filestream setup
var fs = require('fs');
var writeStream =  fs.createWriteStream('mobilehub.html');

var s3 = new AWS.S3();
var s3params = ({
    Bucket: awsmobile.aws_content_delivery_bucket,
    Key: 'index.html'
});

var res = s3.getObject(s3params, function(err, res){
    if (err){
        console.error(err);
    }else {
        writeStream.write(res.Body);
    }
})

Run the following commands to compile your code and execute:

$./node_modules/.bin/babel ./src --experimental --source-maps-inline -d ./dist
$node dist/awstest.js

In your root directory, there is now a file called mobilehub.html. This is the downloaded sample page from your S3 bucket.

Further work

This is a simple example. Look at the other settings available and configure your Mobile Hub project in different ways to see what is available. For instance, you can use this feature to configure Amazon Cognito User Pools or an Amazon API Gateway endpoint backed by AWS Lambda. Let us know what future functionality or examples you’d like us to explore in the comments.

 

 

AWS Mobile App Backend with Hybrid Apps

by Sean Senior | on | Permalink | Comments |  Share

This post was co-authored by Leo Drakopoulos, AWS Solutions Architect.

Today we would like to tell you about a new solutions brief for building serverless mobile backend solutions on AWS, and a step-by-step walkthrough for implementing this pattern, using the Ionic framework on AWS Answers. Like other solutions on AWS Answers, this one was built by AWS Solutions Architects. This solution incorporates best practices for deploying scalable backend services for mobile applications by leveraging AWS managed services.

The Mobile Backend Services brief provides best practices, architectural guidance, and considerations for using managed services on the AWS Cloud to simplify development of RESTful backend services for mobile apps. The walkthrough shows you how to power hybrid mobile applications built using the Ionic Framework. You can use the walkthrough guide to quickly integrate your hybrid mobile application with mobile backend services hosted on AWS. The reference architecture and walkthrough enable you to deploy your Ionic mobile app without having to manage any backend infrastructure. The same general approach can be applied to any framework built using JavaScript, such as PhoneGap/Cordova, Framework 7, etc. Here’s how it looks:

This mobile app backend design applies to both hybrid and native mobile application use cases, including the following:

  • User sign in and registration
  • Saving and retrieving data from a NoSQL store
  • Calling cloud hosted REST APIs from your hybrid mobile application

To enable these use cases, the solution uses Amazon Cognito User Pools to add sign-up, sign-in, and user management for mobile apps. Amazon API Gateway is used to create custom RESTful APIs. These APIs trigger an AWS Lambda function to perform CRUD operations on an Amazon DynamoDB NoSQL data store.

Here is how it works. An Amazon Cognito User Pool authorizer is associated with a RESTful API hosted in Amazon API Gateway. The authorizer authenticates every API call made from a mobile app by leveraging a JSON Web Token (JWT) passed in the API call headers. Amazon API Gateway is natively integrated with Amazon Cognito User Pools so the validation of the JWT requires no additional effort from the application developer. Amazon API Gateway then invokes an AWS Lambda function that accesses other AWS services, which in this case is Amazon DynamoDB. When AWS Lambda is invoked, it assumes an AWS Identity and Access Management (IAM) role. The IAM role determines the level of access that AWS Lambda has to Amazon DynamoDB.

The cost to run this reference implementation in production varies, depending on the scale of your backend services. Some of the services leveraged by the solution are part of the AWS Free Tier, which enables you to get started at a very low cost point. For more information, see AWS Free Tier at https://aws.amazon.com/free/.

The solution brief for the Mobile App Backend is available online or you can download the .pdf version here. You can get started today by downloading the step-by-step walkthrough guide for the reference implementation using the Ionic framework.

Customizing Amazon Cognito User Pool Authentication Flow

Introduction

Modern authentication flows incorporate new challenge types, in addition to a password, to verify the identity of users. For example, these challenge types include CAPTCHAs or dynamic challenge questions. With Amazon Cognito Your User Pools, we now have a flexible authentication flow that you can customize to incorporate additional authentication methods and support dynamic authentication flows that are server driven. First, we generalize authentication into two common steps, which are implemented through two APIs (InitiateAuth and RespondToAuthChallenge). In this flow, a user authenticates by answering successive challenges until authentication either fails or the user is issued tokens. With these two steps, which can be repeated to include different challenges, we support any custom authentication flow. Second, we provide the ability to customize your authentication flow with AWS Lambda triggers. These triggers issue and verify their own challenges as part of the authentication flow.

In this post, we provide detail on the two APIs and their inputs and outputs as we demonstrate how you can customize Your User Pools authentication flow to contain additional challenges such as CAPTCHAs.

New APIs

InitiateAuth

This API kicks off the authentication flow. It explicitly indicates to Amazon Cognito how you are trying to authenticate, along with initial authentication parameters that are passed to the pre-authentication Lambda trigger. With a successful call, the response provides either tokens (for an authenticated user) or a challenge.

The InitiateAuth API has the following inputs:

AuthFlow String

The name of the auth flow is determined by the service. The following are supported: USER_SRP_AUTH, REFRESH_TOKEN_AUTH, CUSTOM_AUTH, ADMIN_NO_SRP_AUTH. USER_SRP_AUTH and REFRESH_TOKEN_AUTH were previously available through other APIs but they are easier to use with the new APIs. For a custom authentication flow, the CUSTOM_AUTH value is provided. For more information on the flows, see Custom Authentication Flow in the Amazon Cognito Developer Guide.

AuthParameters Map of String, String

Key/value pairs containing all of the inputs necessary to initiate this authentication method (e.g., USERNAME=johndoe, SRP_A=AB009809). Based on authentication flow and a combination of some parameters missing, authentication can be failed.

[ClientMetadata] Map of String, String

Optional field. Key/value pairs containing inputs that aren’t authentication parameters but are inputs to the pre-authentication Lambda trigger. Using this Lambda trigger, you can implement custom validations to accept/deny the request, based on, for example, the user context.

ClientId String

The app clientId for the app attempting to authenticate.

RespondToAuthChallenge

Used to respond to challenges, which can include multiple rounds until the user successfully authenticates (and Amazon Cognito issues tokens) or fails. You have control over how many challenge rounds are presented to the user. This can be decided based on the challenges already answered. With each call, the response is either a successful authentication when tokens are issued, a new challenge, or failure of the authentication.

The RespondToAuthChallenge API has the following inputs:

ChallengeName String

Name of the challenge being responded to.

Session String

An encrypted session received by the client in the previous step that the client must pass back as-is. The session contains state information about the current authentication. It cannot be replayed and it expires after 3 minutes.

ChallengeResponses Map of String, String

Key/value pairs containing all of the parameters necessary to respond to the challenge (e.g., captchaAnswer=AZ235F).

ClientId String

ClientId trying to authenticate.

InitiateAuth and RespondToAuthChallenge outputs

A successful call to either of the APIs results in tokens that indicate that the authentication flow is complete, or a challenge with a session and parameters.

AuthenticationResult containing Tokens

If this is the last step in the authentication flow, the result contains ID, access and refresh tokens. For more information, see Using Tokens with User Pools in the Amazon Cognito Developer Guide.

ChallengeName String

Name of the next challenge. For example, possible values can be CUSTOM_CHALLENGE, if a custom challenge needs to be answered, or PASSWORD_VERIFIER, if password verification is required.

Session String

An encrypted session received by the client in the previous step that the client must pass back as-is. The session contains state information about the current authentication. It cannot be replayed and it expires after 3 minutes.

ChallengeParameters Map of String, String

Key/value pairs containing all of the parameters necessary to prompt the user for the returned challenge (e.g., captchaUrl=https://xyz.com/captcha/123415).

Diving into the custom authentication flow

To provide you control over the authentication flow, we introduced a flow of CUSTOM_AUTH type and provided you with Lambda triggers you can use to implement this custom authentication flow. The flow can be broken down into the following decisions that you can customize through Lambda triggers:

  • Analyze the challenges a user has answered so far (successfully or unsuccessfully) and then succeed the authentication (and generate tokens), fail authentication, or prompt the user with a new challenge. This is called the Define Auth Challenge Lambda trigger.
  • Generate a challenge that consists of parameters used to challenge the user and valid answers that can be used when the challenge is answered. This is called the Create Auth Challenge Lambda trigger.
  • Verify if the answer provided by the user is valid. This is called the Verify Auth Challenge Lambda trigger.

Lambda triggers can be entered as code in the AWS Lambda console as shown.

lambda_console

You can configure Lambda triggers in the Amazon Cognito console on the User Pools Triggers page as shown next. When a Lambda trigger is selected in the Amazon Cognito console, the necessary execution rights are created automatically by the console.

configure_lambda

When an app initiates a flow of CUSTOM_AUTH type, Amazon Cognito executes the Define Auth Challenge Lambda trigger to issue a challenge type. This can be a standard (built-in) challenge, such as SRP, that can be handled by the Amazon Cognito service. Or it can be a custom challenge handled by a Lambda trigger that you supply (CUSTOM_CHALLENGE type). In general, this process takes as input the past challenges answered by the user and their result. If the challenge issued is of custom type, Amazon Cognito calls a Lambda trigger to create and issue the challenge. The Lambda trigger passes back the challenge parameters and valid answers. This process is shown in the following two diagrams.

diagram_1

diagram_2

Amazon Cognito User Pools passes the challenge and an encrypted piece of session information back to the client SDK. The client SDK gathers the answers to the challenge and passes back the answers and the encrypted session data as it received it. Amazon Cognito User Pools decrypts the data and calls a Lambda trigger to check if the answers match. Amazon Cognito User Pools then calls the Lambda trigger with the challenges answered so far (adding the challenge just answered). The Lambda trigger can issue a new challenge, issue tokens, or fail authentication, and the process can repeat accordingly. We dive deep into the Lambda contract specifications next.

Lambda Trigger contract specifications

There are three Lambda triggers mentioned previously. We provide detail on the different parameters the Lambda triggers take as inputs and the valid outputs. All three of these Lambda triggers also receive all of the user’s attributes as inputs.

DefineAuthChallenge: The challenges (state machine) Lambda trigger

This Lambda trigger has as input the unencrypted session challenge answering information (it was decrypted by the service after it was passed to and from the client). The trigger then returns a challenge name or a Boolean value that indicates whether Amazon Cognito should issue tokens or not.

Inputs

session List of ChallengeResult objects

This is a list containing ChallengeResult objects that indicate whether the challenge was successfully answered. A ChallengeResult object contains a challenge name (challengeName), a Boolean value with the challenge answering result (challengeResult), and challenge metadata that you populate when you generate a challenge (challengeMetadata).

Outputs

challengeName String

Amazon Cognito returns a new challenge name that the client must answer. Alternatively, Amazon Cognito can issue tokens or fail authentication using the following parameters. If you want to generate a challenge with the Create Auth Challenge Lambda trigger, your trigger must output a challengeName of CUSTOM_CHALLENGE.

issueTokens Boolean

Indicates whether tokens should be issued to the user, which means the user was authenticated.

failAuthentication Boolean

Indicates whether the user’s authentication attempt should be terminated because of a failure to authenticate.

Example Lambda Trigger

This example Lambda trigger issues tokens if SRP_A, PASSWORD_VERIFIER, and CUSTOM_CHALLENGE challenges were passed; otherwise it fails the authentication.

exports.handler = function(event, context) {
    if (event.request.session.length == 1 && event.request.session[0].challengeName == 'SRP_A') {
        event.response.issueTokens = false;
        event.response.failAuthentication = false;
        event.response.challengeName = 'PASSWORD_VERIFIER';
    } else if (event.request.session.length == 2 && event.request.session[1].challengeName == 'PASSWORD_VERIFIER' && event.request.session[1].challengeResult == true) {
        event.response.issueTokens = false;
        event.response.failAuthentication = false;
        event.response.challengeName = 'CUSTOM_CHALLENGE';
    } else if (event.request.session.length == 3 && event.request.session[2].challengeName == 'CUSTOM_CHALLENGE' && event.request.session[2].challengeResult == true) {
        event.response.issueTokens = true;
        event.response.failAuthentication = false;
    } else {
        event.response.issueTokens = false;
        event.response.failAuthentication = true;
    }
    context.done(null, event);
}

CreateAuthChallenge: The challenge generator Lambda trigger

This Lambda trigger takes a challenge name as input and then generates challenge parameters based on that challenge.

Inputs

challengeName String

The name of the challenge the Lambda trigger has been requested to issue.

session List of ChallengeResult objects

This is a list containing ChallengeResult objects that indicate whether the challenge was successfully answered. A ChallengeResult object contains a challenge name (challengeName), a Boolean value with the challenge answering result (challengeResult), and challenge metadata that you populate when you generate a challenge (challengeMetadata).

Outputs

publicChallengeParameters Map of String, String

The Lambda trigger returns a map of public challenge parameters. This map is sent to the client unencrypted so that the client can present the challenge to the user; for example, a CAPTCHA URL.

privateChallengeParameters Map of String, String

The Lambda trigger returns a map of private challenge parameters that it generates. This output is labeled “private” and the client cannot see it. For example, it might be used to hold CAPTCHA answer or other valid answers for the challenge.

challengeMetadata String

Metadata about the challenge. This data is put in the session of challenge results when this challenge is answered.

Example Lambda trigger

The following Lambda trigger generates the publicChallengeParameters and privateChallengeParameters maps, with the URL to a CAPTCHA in the public map and the valid answer to the CAPTCHA in the private map. The two pieces usually come from an external service.

exports.handler = function(event, context) {
    if (event.request.session.length == 2 && event.request.challengeName == 'CUSTOM_CHALLENGE') {
        event.response.publicChallengeParameters = {};
        event.response.publicChallengeParameters.captchaUrl = 'url/123.jpg'
        event.response.privateChallengeParameters = {};
        event.response.privateChallengeParameters.answer = '5';
        event.response.challengeMetadata = 'CAPTCHA_CHALLENGE';
    }
    context.done(null, event);
}

Verify Auth Challenge: The response verifying Lambda Trigger

This Lambda trigger verifies the answers to the challenges. It gets acceptable answers to the challenge, provided by the previous Create Auth Challenge Lambda trigger, and compares them to the client provided answer.

Inputs

privateChallengeParameters – Map of String, String

This input is the same as described previously for the Create Auth Challenge Lambda trigger. Amazon Cognito forwards the map of private challenge parameters from the Create Auth Challenge Lambda trigger to the Verify Auth Challenge Lambda trigger. These parameters include valid answers for the challenge.

challengeAnswer String

The answer provided by the user to the challenge.

Outputs

answerCorrect Boolean

Indicates whether the answer provided to the challenge was correct.

Example Lambda trigger

The following Lambda trigger checks if the challengeAnswer value is equal to an answer entry in the privateChallengeParameters map to determine if the challenge was answered correctly.

exports.handler = function(event, context) {
    if (event.request.privateChallengeParameters.answer == event.request.challengeAnswer) {
        event.response.answerCorrect = true;
    } else {
        event.response.answerCorrect = false;
    }
    context.done(null, event);
}

Client SDK considerations

The client SDKs expose a new callback that requests input from users in the case of custom challenges. The challengeParameters parameter is used to present the challenge to the user and the user’s response is passed back in the challengeResponses parameter to the RespondToAuthChallenge API call. Here is an example in JavaScript to complement the example Lambda triggers described previously. As can be seen in the following, the JavaScript SDK provides a customChallenge callback while the Android and iOS SDKs provide similar callbacks.

var authenticationData = {
    Username : 'username',
    Password : 'password',
};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
var poolData = { 
    UserPoolId : '...', // Your user pool id here
    ClientId : '...' // Your client id here
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
var userData = {
    Username : 'username',
    Pool : userPool
};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.setAuthenticationFlowType(‘CUSTOM_AUTH’);
cognitoUser.authenticateUser(authenticationDetails, {
    onSuccess: function (result) {
      console.log('access token + ' + result.getAccessToken().getJwtToken());
    },

    customChallenge: function (challengeParameters) {
      //gather user responses in challengeResponses based on challengeParameters
      cognitoUser.sendCustomChallengeAnswer(challengeResponses, this);
    },

    onFailure: function(err) {
      alert(err);
    },
});
 
          

Security considerations

The custom user pool authentication flow works in parallel with all other user pool authentication flows, unless you specify otherwise. If you want to implement a custom flow that presents more challenges than, for example, USER_SRP_AUTH, you should choose Only allow Custom Authentication in the Amazon Cognito console, or include the CUSTOM_AUTH_FLOW_ONLY enum in the ExplicitAuthFlows user pool client property.

flag_custom_auth

Conclusions

As you can see, you can customize your authentication flow using the AWS Mobile SDKs. This enables you to create an experience that is designed to provide security and a user-friendly experience for your users. We’d like to hear how you plan to use this feature in your applications, so feel free to leave a comment to share other uses for this feature.

If you have comments or questions, please leave a comment, visit our forums, or post on Stack Overflow.

Using webpack with the Amazon Cognito Identity SDK for JavaScript

by Marc Teichtahl | on | Permalink | Comments |  Share

This blog post is aimed at developers of all experience levels who develop and deploy JavaScript based applications (whether server-side with Node.js or client side) that incorporate the AWS SDK, the Amazon Cognito Identity SDK for JavaScript and who also use the popular webpack module bundler.

In July 2016, Amazon Web Services launched Amazon Cognito User Pools, a feature that makes it easy for developers to add sign-up and sign-in functionality to mobile and web applications. To help developers easily realize the power of user pools within their own applications, we also released the Amazon Cognito Identity SDK for JavaScript.

Amazon Cognito User Pools allows you to easily add user sign-up and sign-in to your mobile and web applications. The fully managed user pool can scale to hundreds of millions of users and you can have multiple directories per AWS account. Creating a user pool takes just a few minutes and allows you to decide exactly which attributes (including address, email, phone number as well as custom attributes) are mandatory and even optional when a new user signs up for your application or service. Your application can also specify the desired password strength, whether the use of Multi-Factor Authentication (MFA) is required, and verify new users via phone number or email address to further enhance the security of your application.

If you are new to the Amazon Cognito Identity SDK for JavaScript this AWS blog post is a great place to start.

Why Use Asset & Module Bundling with the Amazon Cognito Identity SDK for JavaScript

Today, modern web applications for both mobile and desktop have to provide the user with a secure, fast, responsive, and native-app-like experience. There is no doubt that modern browsers are extremely powerful and cater to a vast array of possible implementation approaches. Many of the more popular implementations rely heavily on the deployment of a JavaScript application through some form of asset packaging and/or module bundling. This allows a developer to take their JavaScript application and create one or more files that can be loaded by the client browser by using script tags.

There are many schools of thought on how you can achieve this packaging , including task runners such as Grunt and Gulp, and bundlers such as Browserify. However, there is a general consensus that asset packaging is not only about improving load times—it enables the modularization of your application while ensuring testability and robustness.

Using webpack with the Amazon Cognito Identity SDK for JavaScript

In the many requests we get to provide more detail on how to integrate the Amazon Cognito Identity SDK for JavaScript within a webpack environment, we’re specifically asked how to ensure that webpack correctly manages the following third-party dependencies:

Throughout these examples, the following bower libraries are used by bower.json

"aws-cognito-sdk": "https://raw.githubusercontent.com/aws/amazon-cognito-identity-js/master/dist/aws-cognito-sdk.js",
"amazon-cognito-identity": "https://raw.githubusercontent.com/aws/amazon-cognito-identity-js/master/dist/amazon-cognito-identity.min.js",
"sjcl": "https://raw.githubusercontent.com/bitwiseshiftleft/sjcl/master/sjcl.js",
"jsbn": "https://raw.githubusercontent.com/andyperlitch/jsbn/master/index.js",

For all the reasons we gave earlier for the importance of asset packaging to development processes, and unless your application is extremely small, the use of an asset packaging tool such as webpack is almost always recommended. Of course, one could simply pull in all of these dependencies using tags. However, this would pollute global namespace, and not provide the most optimal resource management and loading approach. Many developers start with a standard webpack.config.js file that has a standard babel loader, as shown here.

{
  /** test for file ending in js or jsx 
   * exclude node_module and bower_components - we dont want to babel these 
   * use the babel loader 
   * apply the react and es2015 (es6) transformations **/

  test: /.jsx?$/,
  exclude: /(node_modules|bower_components)/,
  loader: 'babel',
  query: {
    presets: ['react', 'es2015']
  }
}

It’s important to remember that this configuration doesn’t take into account that some of third-party dependencies used by the Amazon Cognito Identity SDK for JavaScript currently do not use the Universal Module Definition (UMD) pattern for JavaScript.

The UMD pattern attempts to offer Asynchronous Module Definition (AMD) based compatibility with the most popular script loaders of the day such as RequireJS and CommonJS.

This is a pattern that webpack relies on, and so we must make some changes to how webpack loads these modules. Without these changes, you may encounter errors such as the following.

amazon-cognito-identity.min.js:19 Uncaught ReferenceError: BigInteger is not defined

Such an error may be encountered when making a call to AWSCognito.CognitoIdentityServiceProvider.CognitoUser property authenticateUser This is an example of where we can make use of the webpack imports and exports loader capability to overcome this error.

Using webpack Loaders

According to the webpack documentation "loaders allow you to preprocess files as you require() or “load” them. Loaders are kind of like “tasks” are in other build tools, and provide a powerful way to handle front-end build steps. Loaders can transform files from a different language like, CoffeeScript to JavaScript, or inline images as data URLs"

In order to resolve the lack of UMD compatibility, you will rely to two specific loaders, import and export.

Using the Export Loader

In the case of the Amazon Cognito Identity SDK for JavaScript, we need to ensure we export theAWSCognito variables into the scope of the module that requires/imports (for ES6) them.

{
  test: /aws-cognito-sdk/index.js/,
  loader: 'exports?AWSCognito'
}

Using the exports loader has the effect of exporting a module method within bundle created by webpack. As a result, both AWSCognito and AWS are now accessible when required or import(ed) (for ES6).

var AWSCognito = require('aws-cognito-sdk')

/*** EXPORTS from export-loader ***/ 
module.exports = AWSCongito

More information about the exports loader can be found here

Using the Import Loader

The import loader is mostly used to inject (import) variables into the scope of another module. This is especially useful if third-party modules are relying on global variables like BitInteger or sjcl as is the case with Amazon Cognito Identity SDK for JavaScript.

If you don’t use the webpack loader, the following is generated within the bundle.

__webpack_require__(431);       // refers to jsbin
__webpack_require__(432);       // refers to sjcl

Beacuse neither jsbin or sjcl export anything, any calls that rely on these modules will result in an error.

To resolve this, we can use the following webpack loader configuration:

{
  test: /amazon-cognito-identity/index.js/,
  loader: 'imports?jsbn,BigInteger=>jsbn.BigInteger,sjcl'
},
{
  test: /sjcl/index.js/,
  loader: 'imports?sjcl'
}

This injects the following into the bundle (in this case bundle.js) created by webpack.


/*** IMPORTS FROM imports-loader ***/
var jsbn = __webpack_require__(431);
var BigInteger = jsbn.BigInteger;
var sjcl = __webpack_require__(432);

As a result, jsbn, BigInteger and sjcl are all imported from their respective modules into Amazon Cognito Identity SDK for JavaScript.

More information about the import loader can be found here

Next Steps

We encourage you to download the Amazon Cognito Identity SDK for JavaScript and start building your application. Coupled with webpack, and by following the guidance in this blog, you we hope you have a smooth development experience.

If you have any comments or questions, please free to comment below, reach out via email (teichtah@amazon.com) or raise an issue here.

References

This blog post makes reference to the following third party resources