Tag: JavaScript


AWS Mobile App Backend with Hybrid Apps

by Sean Senior | on | | Comments

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

by Ionut Trestian | on | in AWS Mobile | | Comments

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 | | Comments

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

Announcing the AWS SDK for React Native

by Rohan Deshpande | on | | Comments
We’re excited to announce the immediate availability of the developer preview of the AWS SDK for React Native. The source code is available on GitHub under the Apache 2.0 license.
 
The SDK includes support for the following services:
  • Amazon S3 to store user data, including photos and videos, in the cloud. It uses the TransferUtility, which simplifies file transfers between your app and the cloud.
  • Amazon DynamoDB to store data into a NoSQL database.
  • AWS Lambda to run serverless code in the cloud without the need for backend infrastructure.
  • Amazon SNS to send and receive push notifications.
The SDK core uses Amazon Cognito Identity as the authentication provider to comply with best practices for mobile app development.
 

Getting Started with the SDK

To include the SDK in your React Native application:
  1. Download the packages from Github.
  2. Add the services that you need into your package.json.
  3. Run npm install.
Here is a sample package.json that uses AWS Lambda. 
 
% cat package.json
{
  "name": "sample",
  "version": "0.0.1",
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "aws-sdk-react-native-core": "../aws-sdk-react-native-core-0.0.1.tgz",
    "aws-sdk-react-native-lambda": "../aws-sdk-react-native-lambda-0.0.1.tgz",
    "react": "15.3.1",
    "react-native": "0.32.0"
  }
}
 	
See the GitHub repository for sample apps that demonstrate how to use the Cognito functionality to authenticate and the TransferUtility to transmit files to S3.
 

Contributing to the SDK

We welcome issue reports and contributions to the AWS SDK for React Native. Please report issues using the Github issue tracker. To contribute,  submit a pull request to the GitHub repository with a description of your issue or suggested change. If this is a bug fix, please reference the issue and include steps to reproduce it.

 

Accessing Your User Pools using the Amazon Cognito Identity SDK for JavaScript

by Ionut Trestian | on | in AWS Mobile | | Comments

Introduction

In April, we launched the beta version of a new Amazon Cognito feature called Your User Pools. Among other functionality, the User Pools feature makes it easy for developers to add sign-up and sign-in functionality to web apps. AWS Mobile SDKs for Android, JavaScript, and iOS are available with this beta launch. In this blog post we will show you how to access the new functionality by using the Amazon Cognito Identity SDK for JavaScript.

Integrating your user pool into your web app

To integrate this new feature into your app, follow the instructions in the Announcing Your User Pools in Amazon Cognito blog post to create your user pool. Note that Generate client secret must be unchecked when creating a web app; the Amazon Cognito Identity SDK for JavaScript doesn’t support apps that have a client secret simply because the client secret could be easily viewed in your code.

Also for brevity, in this blog post we will focus on the functionality provided by the Amazon Cognito Identity SDK for JavaScript. Information about dependencies and setup instructions can be found in the GitHub repository.

Using your user pool in your web app

The first step for interacting with the new feature is to create a CognitoUserPool object by providing a UserPoolId and a ClientId. As mentioned, the SDK does not support the app client secret. If you configure your user pool app client with an app client secret, the SDK will throw exceptions.

Throughout the examples in this post, we will use the userPool object, the userData object (containing the user pool) and the username object, as shown in the following.

AWSCognito.config.region = 'us-east-1';

var poolData = {
    UserPoolId : '...', // your user pool id here
    ClientId : '...' // your client id here
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
var userData = {
    Username : '...', // your username here
    Pool : userPool
};

After creating a user pool object, users can be signed up for the application. The necessary information about the user can be collected through the web UI and used to populate CognitoUserAttribute objects that are passed in the signUp call.

var attributeList = [];
    
var dataEmail = {
    Name : 'email',
    Value : '...' // your email here
};
var dataPhoneNumber = {
    Name : 'phone_number',
    Value : '...' // your phone number here with +country code and no delimiters in front
};
var attributeEmail = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserAttribute(dataEmail);
var attributePhoneNumber = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserAttribute(dataPhoneNumber);

attributeList.push(attributeEmail);
attributeList.push(attributePhoneNumber);

var cognitoUser;
userPool.signUp('username', 'password', attributeList, null, function(err, result){
    if (err) {
        alert(err);
        return;
    }
    cognitoUser = result.user;
    console.log('user name is ' + cognitoUser.getUsername());
});

After signing up, the user needs to confirm the sign-up by entering a code sent either through SMS or email (based on the user pool settings). Alternatively, you can use a PreSignUp AWS Lambda function to automatically confirm your users. To confirm sign-up, you must collect the code (‘123456’ in the following example) received by the user and use it as follows:

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

The registration code can be resent by using the resendConfirmationCode method of a cognitoUser object. This is an unauthenticated call and only the username, the client ID, and the user pool information are needed.

A confirmed user can authenticate to obtain a session. The session contains an ID token that contains user claims, an access token that is used internally to perform authenticated calls, and a refresh token that is used internally to refresh the session after it expires each hour. For more information about tokens, see Using Tokens with Amazon Cognito Identity User Pools in the Amazon Cognito Developer Guide. When authentication is successful, the onSuccess callback is called. If authentication fails, the onFailure callback is called. If authentication requires MFA, the mfaRequired callback is called. You must invoke sendMFACode on the cognitoUser object. The verification code that is received must be passed and the user is finally authenticated.

var authenticationData = {
    Username : '...', // your username here
    Password : '...', // your password here
};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);

var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
    onSuccess: function (result) {
        console.log('access token + ' + result.getAccessToken().getJwtToken());
    },

    onFailure: function(err) {
        alert(err);
    },
    mfaRequired: function(codeDeliveryDetails) {
        var verificationCode = prompt('Please input verification code' ,'');
        cognitoUser.sendMFACode(verificationCode, this);
    }
});

After authenticating, a user can perform authorized operations such as, retrieve user attributes, verify user attributes (such as an unverified email address), delete user attributes, update user attributes, change the user password, and delete the user’s account. For user pools that have an MFA setting of optional, users can enable or disable MFA just for themselves, at a user level. Signing out from the application clears the local user session so the user must authenticate again to establish a new session.

If users forget their passwords, they can initiate a forgotten password flow. A code will be sent to the user. The user uses this code together with a new password to complete the flow.  The relevant call is forgotPassword on a cognitoUser object that is unauthenticated; the relevant callbacks can be seen in the following.

cognitoUser.forgotPassword({
    onSuccess: function (result) {
        console.log('call result: ' + result);
    },
    onFailure: function(err) {
        alert(err);
    },
    inputVerificationCode() {
        var verificationCode = prompt('Please input verification code ' ,'');
        var newPassword = prompt('Enter new password ' ,'');
        cognitoUser.confirmPassword(verificationCode, newPassword, this);
    }
});

If you want to work with other AWS services, you must first create a federated identity pool. After you create this identity pool, you can get AWS credentials by passing the identity pool ID and the ID token (obtained earlier) when authenticating. The following example shows how to populate IdentityPoolId and pass the ID token through the Logins map.

AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
    Logins: {
        'cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX': result.getIdToken().getJwtToken()
    }
});

AWS.config.credentials.get(function(err){
    if (err) {
        alert(err);
    }
});

More examples and an overview of the code can be found in the GitHub repository. We welcome your feedback on this feature. You can reach us by creating an issue in the GitHub repository or posting to the Amazon Cognito forums.

Use Amazon Mobile Analytics with your JavaScript enabled apps

by Nicholas Beets | on | | Comments

Since our launch of Amazon Mobile Analytics last year, we have heard from many app developers who wanted to use Amazon Mobile Analytics with their apps that are built with JavaScript based frameworks.  To address these requests, we are releasing the Amazon Mobile Analytics SDK for JavaScript today.  With this release you can now integrate Amazon Mobile Analytics with web apps and HTML5 app frameworks.  In this blog post we’ll cover the few steps it takes to get started submitting events from a mobile app using the Amazon Mobile Analytics SDK for JavaScript. 

For those who are not familiar with this service, Amazon Mobile Analytics lets you simply and cost effectively collect and analyze your application usage data. In addition to providing usage summary charts that are available for quick reference, Amazon Mobile Analytics enables you to set up automatic export of your data to Amazon S3 and Amazon Redshift so that you can analyze it directly with SQL queries or combine your data with other data sources. To learn more about Amazon Mobile Analytics click here.

In this blog post, I will go over the main steps to submit events to Amazon Mobile Analytics using PhoneGap as an example. The same general steps can be applied to any framework built around JavaScript such as AppGyver(supersonic), Appcelerator, Ionic, Famo.us, Intel XDK, and web pages.

Before you start, you will need to have Node.js and node package manager (npm) installed. You will also need to have your Amazon Mobile Analytics App ID and Amazon Cognito Identity Pool ID on hand. To get a new App ID and Cognito Identity Pool ID, simply log into the Amazon Mobile Analytics console and select “Add an App” from the drop down menu and complete the steps to create a new app. After following the instructions, you will end up with a Cognito Identity Pool ID and an Amazon Mobile Analytics App ID which you will need later.

In the following steps, we will create a new PhoneGap app and integrate Amazon Mobile Analytics with that app.

Step 1: Install PhoneGap

PhoneGap is a framework for developing mobile apps by using HTML, JavaScript and CSS.  It can be installed via the Node Package Manager (npm). Please see the PhoneGap web site for more information about installing and using PhoneGap to create mobile apps.

Open a command prompt window and type the following command to install the PhoneGap command line interface (CLI):

npm install -g phonegap

Step 2: Create a PhoneGap App

Type these commands for PhoneGap to generate your app skeleton using the command line interface (CLI).

phonegap create my-app
cd my-app

Step 3: Load the Amazon Mobile Analytics JavaScript SDK

The Amazon Mobile Analytics SDK for JavaScript depends on functions within the AWS SDK for JavaScript so you will need to download both. You can download the AWS SDK for JavaScript here and the Amazon Mobile Analytics SDK for JavaScript here.

Now copy the aws-sdk.min.js and aws-sdk-mobile-analytics.min.js into your PhoneGap project under the /www/js directory.

Next, load the SDKs by adding the following script tags to /www/index.html (make sure to update the version to match the versions that were downloaded).

  <script type="text/javascript" src="js/aws-sdk.min.js"></script>
  <script type="text/javascript" src="js/aws-sdk-mobile-analytics.min.js"></script>

Be sure to place those two lines before the index.js script tag below:

  <script type="text/javascript" src="js/index.js"></script>

This is what the /www/index.html body tag would look like with all of the changes:

    <body>
        <div class="app">
            <h1>PhoneGap</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>
        <script type="text/javascript" src="js/aws-sdk.min.js"></script> 
        <script type="text/javascript" src="js/aws-sdk-mobile-analytics.min.js"></script>
        <script type="text/javascript" src='cordova.js'></script>
        <script type="text/javascript" src="js/index.js"></script>
        <script type="text/javascript">
            app.initialize();
        </script>
    </body>
 

Next, add an entry to the /config.xml file that allows your app to make calls to AWS services. Open the config.xml file and add an access tag as follows:

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.myapp" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <!-- ... -->
    <access origin="*.amazonaws.com" />
    <!-- ... -->
</widget>

Step 4: Initialize the Amazon Mobile Analytics JavaScript SDK

Open the /www/js/index.js file.  We’ll need to add a few lines in the onDeviceReady function.

First, add the Cognito Identity Credentials by adding the following lines to the  (replace “YOUR_IDENTITY_POOL_ID” with your Cognito Identity Pool ID).

AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'YOUR_IDENTITY_POOL_ID'
}); 

Next, load the credentials and initialize the client by adding the following (replace “YOUR_MOBILE_ANALYTICS_APP_ID” with your Amazon Mobile Analytics App ID). Note that the valid values for the platform attribute are ‘iPhoneOS’ and ‘Android’.  For a list of all options, please see the following documentation.

var options = {
    appId : 'YOUR_MOBILE_ANALYTICS_APP_ID',
    platform: 'Android',
    logger: console //Remove this line to turn off log messages 
};
this.mobileAnalyticsClient = new AMA.Manager(options);
console.log('Analytics initialized');

Step 5: Submit Events

At this point you can use the Amazon Mobile Analytics SDK for JavaScript to submit events.  By default, the SDK will set the Session Length to 10 minutes (you can change this by setting the sessionLength option).  Let’s hook into the PhoneGap lifecycle events and send a stop event when the app loses focus.  The MobileAnalyticsManager provides special helper functions for stopping and starting sessions.

document.addEventListener('pause', this.mobileAnalyticsClient.stopSession.bind(this.mobileAnalyticsClient), false); 
document.addEventListener('resume', this.mobileAnalyticsClient.startSession.bind(this.mobileAnalyticsClient), false);

You can record custom events by calling the recordEvent function. Let’s record a custom event anytime the user touches the screen and record how many times it has been touched.  We’ll start with the function to record the event and a variable to track the number of touches on the main screen. Add the following code to record a custom event to your app object:

touchCount: 0,
recordTouchEvent: function(event) {
    console.log(this.mobileAnalyticsClient.recordEvent('customTouch', { 
        'screenName': 'main'}, {'touchCount': this.touchCount++ } ));
    console.log('TouchEvent received');
}

Next, we’ll add an event listener for touches and tell it to use our recordTouchEvent function as the callback. Add this call to the end of your onDeviceReady function

document.addEventListener('touchstart', this.recordTouchEvent.bind(this), false);

Here is what the /www/js/index.js app object would look like with all of the changes:

var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
 
        console.log('Analytics initializing');
        AWS.config.region = 'us-east-1';
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: 'YOUR IDENTITY POOL ID'
        });
 
        var options = {
            appId : 'YOUR MOBILE ANALYTICS APP ID',
            platform: 'Android',
            logger: console //Remove this line to turn of log messages 
        };
        this.mobileAnalyticsClient = new AMA.Manager(options);
        console.log('Analytics initialized');
 
        document.addEventListener('pause', this.mobileAnalyticsClient.stopSession.bind(this.mobileAnalyticsClient), false);
        document.addEventListener('resume', this.mobileAnalyticsClient.startSession.bind(this.mobileAnalyticsClient), false);
        document.addEventListener('touchstart', this.recordTouchEvent.bind(this), false);
    },
    touchCount: 0,
    recordTouchEvent: function(event) {
        console.log(this.mobileAnalyticsClient.recordEvent('customTouch', { 
            'screenName': 'main'}, {'touchCount': this.touchCount++ } ));
        console.log('Touch Event recorded');
    },
 
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');
 
        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');
 
        console.log('Received Event: ' + id);
    }
};

Step 6: Test on physical devices

Now you can test your app on physical devices using the PhoneGap Developer App.  

Start by running the following command

phonegap serve --port 3000 --no-autoreload

Once you’ve installed the Phone Gap Developer App from the app store onto your device, you can enter the IP address and Connect to see your new app.

You can find the IP address to connect to in the output of the “phonegap serve” command.

[phonegap] starting app server…
[phonegap] listening on 192.168.1.100:3000
[phonegap]
[phonegap] ctrl-c to stop the server
[phonegap]

Tap the screen to create customTouch events. With logging enabled, you should see messages related to activity with the Amazon Mobile Analytics service.

[phonegap] [console.log] TouchEvent received
[phonegap] [console.log] [Function:(AMA.Client).submitEvents]
[phonegap] [console.log] 1 events to be submitted
[phonegap] [console.log] [Function:(AMA.Client).submitEvents]
.
.
.
[phonegap] 202 https://mobileanalytics.us-east-1.amazonaws.com/2014-06-05/events

You can expect to see your events in the Amazon Mobile Analytics dashboard within 60 minutes.

Summary

With today’s release, you can now build apps that use Amazon Mobile Analytics with iOS, Android, FireOS, Unity and JavaScript.  While we used PhoneGap for this tutorial, the same general steps above can also be applied to any framework built around JavaScript (such as AppGyver(supersonic), Appcelerator, Ionic, Famo.us and Intel XDK).  Leave us a comment here and let us know how your integration with the new Amazon Mobile Analytics SDK for JavaScript worked for you and tell us what you’d like us to add next.

Use Amazon Cognito in your website for simple AWS authentication

by Stefano Buliani | on | | Comments

Amazon Cognito helps you create unique identifiers for your end users that are kept consistent across devices and platforms. Cognito also delivers temporary, limited-privilege credentials to your application to access AWS resources.

Over the past few weeks, the team has been working hard to provide access to Amazon Cognito through other AWS SDKs on top of the AWS Mobile SDK for iOS and Android. This is important for us because it allows Amazon Cognito to bridge the gap between the web and mobile worlds. Cognito APIs are now available in the AWS SDK for Java, .NET, PHP and JavaScript, both Node.js and Browser.

By using Amazon Cognito in your web applications as well as mobile apps, you can utilize a consistent, cross-platform identifier for your end users authenticated through Facebook, Google, or Amazon; together with the Cognito Sync service, this allows you to keep user-related data consistent across all your applications and platforms. Further, Cognito helps you to retrieve temporary, limited-privilege credentials for both your authenticated and unauthenticated users without managing any backend infrastructure. In our previous post, we covered how to connect to the Amazon Cognito Identity service from your mobile applications.

Getting started

The first step is to create a new identity pool through the Amazon Cognito console. During the creation of the identity pool, you will be asked to create a new IAM role or pick an existing one for your end users. The role you select has an impact on which AWS services your end users will be able to access with the temporary credentials. A new policy created by the Amazon Cognito console by default allows access to the Amazon Cognito sync service and Mobile Analytics.

The authentication flow

AWS authentication with Amazon Cognito involves three steps:

  1. Call the GetId API providing your AWS account and identity pool details to retrieve a unique identifier for your end user.
  2. Call the GetOpenIdToken API to receive a valid OpenId Connect token for the unique identifier you retrieve with the GetId call.
  3. Using the STS client make an AssumeRoleWithWebIdentity call to retrieve a set of temporary, limited-privilege credentials you can use to access your AWS resources.

See the Amazon Cognito Identity API reference to learn more about these and other API endpoints exposed by the Cognito service.

The JavaScript SDK abstracts this complexity by exposing a CognitoIdentityCredentials object that takes care of making all of the required API calls, caching the unique identifier for the end user received from the GetId call and renewing the credentials from the AssumeRoleWithWebIdentity call when they expire.

To utilize the Java, .NET, or PHP SDK, you have to implement the authentication flow yourself by making the three API calls. This post guides you through that process.

Using JavaScript

The JavaScript SDK for the Browser includes a CognitoIdentityCredentials object, which abstracts the entire authentication flow. This means you don’t have to call all of the APIs individually but simply utilize the CognitoIdentityCredentials object, pass your identity pool and account parameters, and the credentials object takes care of retrieving AWS credentials and the unique identifier for your end users.

JavaScript

// The parameters required to intialize the Cognito Credentials object.
// If you are authenticating your users through one of the supported
// identity providers you should set the Logins object with the provider
// tokens. For example:
// Logins: {
//   graph.facebook.com : facebookResponse.authResponse.accessToken
// }
var params = {
	IdentityPoolId: "YOUR_COGNITO_IDENTITY_POOL_ID"
};

// set the Amazon Cognito region
AWS.config.region = 'us-east-1';
// initialize the Credentials object with our parameters
AWS.config.credentials = new AWS.CognitoIdentityCredentials(params);

// We can set the get method of the Credentials object to retrieve
// the unique identifier for the end user (identityId) once the provider
// has refreshed itself
AWS.config.credentials.get(function(err) {
	if (err) {
		console.log("Error: "+err);
		return;
	}
	console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);

	// Other service clients will automatically use the Cognito Credentials provider
	// configured in the JavaScript SDK.
	var cognitoSyncClient = new AWS.CognitoSync();
	cognitoSyncClient.listDatasets({
		IdentityId: AWS.config.credentials.identityId,
		IdentityPoolId: "YOUR_COGNITO_IDENTITY_POOL_ID"
	}, function(err, data) {
		if ( !err ) {
			console.log(JSON.stringify(data));
		}
	});
});

GetID

The first call you should make is to retrieve a unique identifier for your user. You only need to make this API call the first time a user connects to your app. You should then cache the identity id returned. If a user with a known identity id connects again, you can skip this call. This call can receive an optional parameter containing the tokens returned by the supported identity providers.

Java

// import the required packages from the AWS SDK for Java
import com.amazonaws.services.cognitoidentity.*;
import com.amazonaws.services.cognitoidentity.model.*;
import com.amazonaws.services.securitytoken.*;
import com.amazonaws.services.securitytoken.model.*;
import com.amazonaws.auth.*;

// initialize the Cognito identity client with a set
// of anonymous AWS credentials
AmazonCognitoIdentity identityClient = new AmazonCognitoIdentityClient(new AnonymousAWSCredentials());
			
// send a get id request. This only needs to be executed the first time
// and the result should be cached.
GetIdRequest idRequest = new GetIdRequest();
idRequest.setAccountId("YOUR_AWS_ACCOUNT_ID");
idRequest.setIdentityPoolId("YOUR_COGNITO_IDENTITY_POOL_ID");
// If you are authenticating your users through an identity provider
// then you can set the Map of tokens in the request
// Map providerTokens = new HashMap();
// providerTokens.put("graph.facebook.com", "facebook session key");
// idRequest.setLogins(providerTokens);
			
GetIdResult idResp = identityClient.getId(idRequest);
			
String identityId = idResp.getIdentityId();

// TODO: At this point you should save this identifier so you won't
// have to make this call the next time a user connects

.NET

// import the libraries we need from the AWS SDK for .NET
using Amazon;
using Amazon.Runtime;
using Amazon.CognitoIdentity;
using Amazon.CognitoIdentity.Model;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;

// initialize a set of anonymous AWS credentials for our API calls
AnonymousAWSCredentials cred = new AnonymousAWSCredentials ();

// initialize the Cognito identity client and prepare a request object
// to get the identity id
AmazonCognitoIdentityClient cognitoClient = new AmazonCognitoIdentityClient(
	cred, // the anonymous credentials
	RegionEndpoint.USEast1 // the Amazon Cognito region
);

GetIdRequest idRequest = new GetIdRequest ();
idRequest.AccountId = "YOUR_AWS_ACCOUNT_ID";
idRequest.IdentityPoolId = "YOUR_COGNITO_IDENTITY_POOL_ID";
// set the Dictionary of logins if you are authenticating users 
// through an identity provider
//idRequest.Logins = new Dictionary {
// 	{ "graph.facebook.com", "FacebookSessionToken" }
//};

// The identity id is in the IdentityId parameter of the response object
GetIdResponse idResp = cognitoClient.GetId (idRequest);

// TODO: At this point you should save this identifier so you won't
// have to make this call the next time a user connects

PHP

// include the AWS client library in your code
require "aws.phar";
use AwsCognitoIdentityCognitoIdentityClient;
use AwsStsStsClient;

// initialize a Cognito identity client using the factory
$identityClient = CognitoIdentityClient::factory(array(
    'region'  => 'us-east-1'
));

// call the GetId API with the required parameters
$idResp = $identityClient->getId(array(
	'AccountId' => 'YOUR_AWS_ACCOUNT_ID',
	'IdentityPoolId' => 'YOUR_COGNITO_IDENTITY_POOL_ID',
	// If you are authenticating your users through an identity
	// provider then you can set the associative array of tokens
	// in this call
	// 'Logins' => array(
	//	'graph.facebook.com' => 'your facebook session token',
	//)
));

// retrieve the identity id from the response data structure
$identityId = $idResp["IdentityId"];

// TODO: At this point you should save this identifier so you won't
// have to make this call the next time a user connects

GetOpenIdToken

Once you have retrieved the unique identifier for your end user, or loaded the previous identifier from your cache, you can make the GetOpenIdToken call to retrieve a valid OpenID Connect token for them. The token returned by this call can be traded to the Security Token Service (STS) in exchange for temporary, limited-privilege AWS credentials.

If your identity id has already been authenticated with any supported provider – such as Facebook, Google, or Amazon – you will need to include at least one token for a login linked to this identity in the Logins map.

Java

// Create the request object
GetOpenIdTokenRequest tokenRequest = new GetOpenIdTokenRequest();
tokenRequest.setIdentityId(identityId);
// If you are authenticating your users through an identity provider
// then you can set the Map of tokens in the request
// Map providerTokens = new HashMap();
// providerTokens.put("graph.facebook.com", "facebook session key");
// tokenRequest.setLogins(providerTokens);
			
GetOpenIdTokenResult tokenResp = identityClient.getOpenIdToken(tokenRequest);
// get the OpenID token from the response
String openIdToken = tokenResp.getToken();

.NET

// create a new request object
GetOpenIdTokenRequest openIdReq = new GetOpenIdTokenRequest ();
openIdReq.IdentityId = idResp.IdentityId;
// set the Dictionary of logins if you are authenticating users 
// through an identity provider
//openIdReq.Logins = new Dictionary {
// 	{ "graph.facebook.com", "FacebookSessionToken" }
//};
			
GetOpenIdTokenResponse openIdResp = cognitoClient.GetOpenIdToken(openIdReq);

// the authentication token is available in the Token property
// of the response object

PHP

// execute the getOpenIdToken call with the identityId
// retrieved from the previous call or cached
$tokenResp = $identityClient->getOpenIdToken(array(
	'IdentityId' => $identityId,
	// If you are authenticating your users through an identity
	// provider then you can set the associative array of tokens
	// in this call
	// 'Logins' => array(
	//	'graph.facebook.com' => 'your facebook session token',
	//)
));

// read the OpenID token from the response
$token = $tokenResp["Token"];

AssumeRoleWithWebIdentity

This call to the Security Token Service retrieves a set of temporary, limited-privilege credentials for your application to access AWS Resources. The permissions associated to these credentials are set by the IAM access policy set on the role. You can additionally specify a “scope-down” policy on this API call to further restrict access. If your application is allowing access to unauthenticated users, i.e., users that did not log in with your application through an identity provider, we recommend you restrict access as much as possible.

Java

// you can now create a set of temporary, limited-privilege credentials to access
// your AWS resources through the Security Token Service utilizing the OpenID
// token returned by the previous API call. The IAM Role ARN passed to this call
// will be applied to the temporary credentials returned
AWSSecurityTokenService stsClient = new AWSSecurityTokenServiceClient(new AnonymousAWSCredentials());
AssumeRoleWithWebIdentityRequest stsReq = new AssumeRoleWithWebIdentityRequest();
stsReq.setRoleArn("arn:aws:iam::6157xxxxxxxx:role/a_valid_aws_role_arn");
stsReq.setWebIdentityToken(awsAccessToken);
stsReq.setRoleSessionName("AppTestSession");
			
AssumeRoleWithWebIdentityResult stsResp = stsClient.assumeRoleWithWebIdentity(stsReq);
Credentials stsCredentials = stsResp.getCredentials();

// Create the session credentials object
AWSSessionCredentials sessionCredentials = new BasicSessionCredentials(
	stsCredentials.getAccessKeyId(),
	stsCredentials.getSecretAccessKey(),
	stsCredentials.getSessionToken()
);
// save the timeout for these credentials 
Date sessionCredentialsExpiration = stsCredentials.getExpiration();

// these credentials can then be used to initialize other AWS clients,
// for example the Amazon Cognito Sync client
AmazonCognitoSync syncClient = new AmazonCognitoSyncClient(sessionCredentials);
ListDatasetsRequest syncRequest = new ListDatasetsRequest();
syncRequest.setIdentityId(idResp.getIdentityId());
syncRequest.setIdentityPoolId("YOUR_COGNITO_IDENTITY_POOL_ID");
ListDatasetsResult syncResp = syncClient.listDatasets(syncRequest);

.NET

// create a new security token service client with the 
// anonymous credentials we initialized in the first step
AmazonSecurityTokenServiceClient stsClient = new AmazonSecurityTokenServiceClient(
	cred, 
	RegionEndpoint.USEast1
);

// create a new AssumeRoleWithWebIdentityRequest object and set
// the parameters we need
AssumeRoleWithWebIdentityRequest stsReq = new AssumeRoleWithWebIdentityRequest();
stsReq.RoleArn = "arn:aws:iam::6157xxxxxxxx:role/a_valid_aws_role_arn";
stsReq.RoleSessionName = "AppTestSession"; // you need to give the session a name
stsReq.WebIdentityToken = openIdResp.Token; // the Token from the previous API call

// execute the request and retrieve the credentials			
AssumeRoleWithWebIdentityResponse stsResp = stsClient.AssumeRoleWithWebIdentity(stsReq);

// you can now initialize other AWS clients with these credentials,
// for example the Amazon Cognito Sync client
AmazonCognitoSyncClient cognitoSyncClient = new AmazonCognitoSyncClient (stsResp.Credentials);
ListDatasetsRequest syncRequest = new ListDatasetsRequest ();
syncRequest.IdentityId = idResp.IdentityId;
syncRequest.IdentityPoolId = "us-east-1:6df80629-0e7e-432f-a730-23898c0e3901";
ListDatasetsResult syncResp = cognitoSyncClient.ListDatasets(syncRequest);

PHP

// create a new STS client
$stsClient = StsClient::factory(array(
    'region'  => 'us-east-1'
));

// run the AssumeRoleWithWebIdentity request with the IAM role
// for your user and the OpenID token retrieved from the previous
// API call
$stsResp = $stsClient->assumeRoleWithWebIdentity(array(
    'RoleArn' => 'arn:aws:iam::6157xxxxxxxx:role/a_valid_aws_role_arn',
    'RoleSessionName' => 'AppTestSession', // you need to give the session a name
    'WebIdentityToken' => $token
));

// you can use the credentials from the STS call response to 
// initialize other AWS clients. For example the Amazon Cognito Sync client
$cognitSync = CognitoSyncClient::factory(array(
	'key'    => $stsResp['Credentials']['AccessKeyId'],
	'secret' => $stsResp['Credentials']['SecretAccessKey'],
	'token'  => $stsResp['Credentials']['SessionToken'],
	'region' => 'us-east-1'
));
$syncResp = $cognitoSync->listDatasets(array(
	'IdentityId'    => $identityId,
	'IdentityPoolId' => 'YOUR_COGNITO_IDENTITY_POOL_ID'
));

Conclusion

Amazon Cognito makes it simple to securely access your AWS resources from your web applications as well as mobile apps by delivering temporary, limited-privilege credentials. Further, you can keep a consistent end-user identifier in both your web and mobile applications without setting up any infrastructure and managing a backend service. You can also utilize the Amazon Cognito Sync service to save profile data for a user and make it easily accessible from all the platforms supported by your application. The next post will explain how to make the most of the fine-grained access permissions in IAM policies utilizing the Cognito identifier.