AWS Mobile Blog

Using Amazon DynamoDB Document API with the AWS Mobile SDK for Android – Part 2

In the first part of this blog, we introduced you to the Amazon DynamoDB Document API. This API is a mechanism for accessing data in DynamoDB that doesn’t require you to map models to the data. Instead, you access the data through standard accessor methods on a standard Document object. In this blog post, we show how to integrate this functionality into a real application. The application for this demonstration is an Android memo app. The mobile backend architecture for the app is shown in the following diagram.

The services used are:

This infrastructure can be easily set up using AWS Mobile Hub.  Either click the Deploy to AWS Mobile Hub button in our GitHub repository or follow these instructions:

  1. Click Create a new Project in the AWS Mobile Hub console.  Provide a name for your project.
  2. Click NoSQL Database.
  3. Click Enable NoSQL.
  4. Click Add a new table.
  5. Click Start with an example schema.
  6. Select Notes as the example schema.
  7. Select Public for the permissions (we won’t add sign-in code to this app).
  8. Click Create Table, and then click Create Table in the dialog box.

Even though the table you created has a userID, the data is stored unauthenticated in this example. If you were to use this app in production, use Amazon Cognito to sign the user in to your app, and then use the userID to store the authenticated data.

In the left navigation pane, click Resources. AWS Mobile Hub created an Amazon Cognito identity pool, an IAM role, and a DynamoDB database for your project. Mobile Hub also linked the three resources according to the permissions you selected when you created the table. For this demo, you need the following information:

  • The Amazon Cognito identity pool ID (for example, us-east-1:f9d582af-51f9-4db3-8e36-7bdf25f4ee07)
  • The name of the Notes table (for example, androidmemoapp-mobilehub-1932532734-Notes)

These are stored in the application code and used when connecting to the database.

Now that you have a mobile app backend, it’s time to look at the frontend. We have a memo app that you can download from GitHub. First, add the required libraries to the dependencies section of the application build.gradle file:

compile 'com.amazonaws:aws-android-sdk-core:2.4.4'
compile 'com.amazonaws:aws-android-sdk-ddb:2.4.4'
compile 'com.amazonaws:aws-android-sdk-ddb-document:2.4.4'

Add the INTERNET, ACCESS_NETWORK_STATE, and ACCESS_WIFI_STATE permissions to AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

Set up the connection to the Amazon DynamoDB table by creating an Amazon Cognito credentials provider (for appropriate access permissions), and then creating a DynamoDbClient object. Finally, create a table reference:

// Create a new credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
        context, COGNITO_POOL_ID, COGNITO_REGION);

// Create a connection to DynamoDB
dbClient = new AmazonDynamoDBClient(credentialsProvider);

// Create a table reference
dbTable = Table.loadTable(dbClient, DYNAMODB_TABLE);

You can now perform CRUD (Create, Read, Update, Delete) operations on the table:

/**
 * create a new memo in the database
 * @param memo the memo to create
 */
public void create(Document memo) {
    if (!memo.containsKey("userId")) {
        memo.put("userId", credentialsProvider.getCachedIdentityId());
    }
    if (!memo.containsKey("noteId")) {
        memo.put("noteId", UUID.randomUUID().toString());
    }
    if (!memo.containsKey("creationDate")) {
        memo.put("creationDate", System.currentTimeMillis());
    }
    dbTable.putItem(memo);
}

/**
 * Update an existing memo in the database
 * @param memo the memo to save
 */
public void update(Document memo) {
    Document document = dbTable.updateItem(memo, new UpdateItemOperationConfig().withReturnValues(ReturnValue.ALL_NEW));
}

/**
 * Delete an existing memo in the database
 * @param memo the memo to delete
 */
public void delete(Document memo) {
    dbTable.deleteItem(
        memo.get("userId").asPrimitive(),   // The Partition Key
        memo.get("noteId").asPrimitive());  // The Hash Key
}

/**
 * Retrieve a memo by noteId from the database
 * @param noteId the ID of the note
 * @return the related document
 */
public Document getMemoById(String noteId) {
    return dbTable.getItem(new Primitive(credentialsProvider.getCachedIdentityId()), new Primitive(noteId));
}

/**
 * Retrieve all the memos from the database
 * @return the list of memos
 */
public List<Document> getAllMemos() {
    return dbTable.query(new Primitive(credentialsProvider.getCachedIdentityId())).getAllResults();
}

There are two mechanisms for searching the dataset: scan and query. The query() method uses indexed fields within the DynamoDB table to rapidly retrieve the appropriate information. The scan() method is more flexible. It allows you to search on every field, but it can run into performance issues when searching large amounts of data. This results in a worse experience for your users because data retrieval will be slower. For the best experience, index fields that you intend to search often and use the query() method.

The Notes schema in DynamoDB usually segments data on a per-user basis. The app works with both authenticated and unauthenticated users by using the .getCachedIdentityId() method. This method stores the current user identity with every new note that is created.

Android does not allow you to perform network requests on the main UI thread. You must wrap each operation in an AsyncTask. For example:

/**
 * Async Task to create a new memo into the DynamoDB table
 */
private class CreateItemAsyncTask extends AsyncTask<Document, Void, Void> {
    @Override
    protected Void doInBackground(Document... documents) {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(EditActivity.this);
        databaseAccess.create(documents[0]);
        return null;
    }
}

You can initiate a save operation by instantiating the appropriate AsyncTask and then calling .execute():

/**
 * Event Handler called when the Save button is clicked
 * @param view the initiating view
 */
public void onSaveClicked(View view) {
    if (memo == null) {
        Document newMemo = new Document();
        newMemo.put("content", etText.getText().toString());
        CreateItemAsyncTask task = new CreateItemAsyncTask();
        task.execute(newMemo);
    } else {
        memo.put("content", etText.getText().toString());
        UpdateItemAsyncTask task = new UpdateItemAsyncTask();
        task.execute(memo);
    }
    // Finish this activity and return to the prior activity
    this.finish();
}

Similarly, you can retrieve a list of memos on an AsyncTask and pass the memos back to a method in the MainActivity to populate the UI:

/**
 * Async Task for handling the network retrieval of all the memos in DynamoDB
 */
private class GetAllItemsAsyncTask extends AsyncTask<Void, Void, List<Document>> {
    @Override
    protected List<Document> doInBackground(Void... params) {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(MainActivity.this);
        return databaseAccess.getAllMemos();
    }

    @Override
    protected void onPostExecute(List<Document> documents) {
        if (documents != null) {
            populateMemoList(documents);
        }
    }
}

You can find this sample in our GitHub repository. To run the sample:

  1. Open the project in Android Studio.
  2. Open the DatabaseAccess.java file.
  3. Replace the temporary string for COGNITO_POOL_ID with your Amazon Cognito Identity Pool ID.
  4. Replace the temporary string for DYNAMODB_TABLE with your Amazon DynamoDB table name.
  5. If necessary, replace the COGNITO_REGION with the region for your Amazon Cognito identity pool ID.
  6. Run the app on a real device or the Android emulator.

If you are successful, the app looks like the following:

The Document API is currently in beta. We would like to hear about the use cases you want us to support. You can leave your feedback and issues on our forums and GitHub.

Deploy to AWS Mobile Hub from your GitHub repository

by Bharath Kumar | on | Permalink | Comments |  Share

AWS Mobile Hub now helps you share your Mobile Hub project configuration template with other developers. With one click, you can import the project configuration from a GitHub repository into the AWS Mobile Hub console and deploy an identical mobile backend. In addition to one-click import, you can export your project configuration, commit to GitHub, and provide your project configuration as a one-click from your GitHub repository.

Importing a shared project configuration from a GitHub repository

Importing a shared project configuration from a GitHub repository

  1. Click the Deploy to AWS Mobile Hub button in the AWS Mobile community discussion GitHub repository. This button imports the shared project configuration to the AWS Mobile Hub console.
  2. You are prompted to sign in if you have not already done so.

Importing a shared project configuration from a GitHub repository

  1. After you sign in, you are prompted to name your imported project. You can accept the default or create your own name.
  2. Click Import project to deploy the backend configuration specified in the imported project configuration file.

Importing a shared project configuration from a GitHub repository

  1. After importing the project, click integrate with my app for the integration instructions. Either download the sample app, which demonstrates each feature, or integrate the AWS Mobile SDK into your own app.

Create a project configuration that can be shared from a GitHub repository

Create a project configuration that can be shared from a GitHub repository

  1. In the AWS Mobile Hub console, hover over the dots in the upper right of the card for the project you want to share.
  2. Select Export(file).
  3. Download the .zip file to your local computer. The .zip file contains a YAML file that has the backend configuration of your exported project.
  4. Check in the .zip file or the YAML file to your GitHub repository.
  5. Add a button to your GitHub repository’s README file with the following information:
<p>
<a target="_blank" href="https://console.aws.amazon.com/mobilehub/home?#/?config=<GITHUB_URL_TO_ZIP_OR_YAML_FILE>">
<span>
    <img height="100%" src="https://s3.amazonaws.com/deploytomh/button-deploy-aws-mh.png"/>
</span>
</a>
</p>
  1. Replace GITHUB_URL_TO_ZIP_OR_YAML_FILE with the actual GitHub URL to the checked-in .zip or YAML file.

Now any developer can import the backend configuration of your exported project from your GitHub repository into the AWS Mobile Hub console and build a mobile application.

For more information, see Cloning, Exporting, and Importing AWS Mobile Hub Projects in the AWS Mobile Hub Developer Guide. As always, feel free to contact us on the AWS Forums if you have questions or issues.

Using Amazon DynamoDB Document API with AWS Mobile SDK for Android – Part 1

The AWS Mobile SDK for Android helps developers write mobile apps by providing simplified APIs for using AWS services, such as Amazon Cognito and Amazon DynamoDB. In the past, to access data, you needed to use the DynamoDB Object Mapper (or use the service APIs). You then had to define a model within your mobile code that mirrors the model defined in the table for DynamoDB. This meant more code to write and test. With v2.4.4 of the SDK, we are introducing a new feature, which we call the Document API. With the Document API, you no longer need to use the DynamoDB Object Mapper; instead, you access individual fields within data objects directly.

What is the difference between the Object Mapper and the Document API?

The Document API provides a simplified interface to access the NoSQL data that is returned by DynamoDB. You no longer need to update schema or map the table properties to class members. The Document API provides new data types to assist in the serialization and deserialization process. The DynamoDB Object Mapper maps client-side model classes to DynamoDB tables.

Both APIs provide methods to perform create / update / delete (CRUD) operations and execute queries against the DynamoDB tables. The difference between the two APIs is in how the data is represented as you manipulate it within your mobile app.  This enables you to select the API that you feel is better for your situation. You can even mix and match. For example, you can use the Object Mapper for data in one table, and use the Document API for data in another table.

Working with the Document Object

When working with the Document API, you primarily work with a Document. A Document is the container for the data returned from or pushed to the Amazon DynamoDB database.

You can convert between JSON and Document objects. However, you will lose fidelity when converting from a Document object to JSON. This is because not all data types that can be stored in DynamoDB can be represented in JSON. Use Document.fromJson() and Document.toJson() to perform the conversion. For example:

Document myDocumentObject = Document.fromJson(myJsonString);
String myJsonString = Document.toJson(myDocumentObject);

The Document object accepts standard JSON types, like string, number, or Boolean:

Document doc = new Document();
doc.put(“stringField”, “value”);
doc.put(“numberField”, 2.0F);
doc.put(“booleanField”, true);

The Document object also accepts JSON arrays (represented as a set of items) and JSON maps (represented as another Document):

// An unordered list
Set<String> coll = new HashSet<String>();
coll.add(“string1”);
coll.add(“string2”);
doc.put(“arrayField”, coll);

// A key-value map
Document name = new Document();
name.put(“first”, “Adrian”);
name.put(“last”, “Hall”);
doc.put(“name”, name);

The Document object also accepts Amazon DynamoDB types, such as binary data, null, and ordered lists:

//null field
doc.put(“nullField”, DynamoDbNull.NULL);

// Binary Data
ByteBuffer buffer = new ByteBuffer();

// Populate the buffer with binary data
doc.put(“binaryField”, new Primitive(buffer));

// An Ordered List
DynamoDbList ddl = new DynamoDbList();
ddl.add(“string1”);
ddl.add(“string2”);
doc.put(“orderedList”, ddl);

You can access data within a Document object using the document path. For example:

String stringField = doc.get(“stringField”);
String firstName = doc.get(“name.first”);

If you do not know which data type is being returned, use the DynamoDbEntry type, and then compare it against the known types:

DynamoDBEntry entry = doc.get(“orderedList”);
If (entry instanceof DynamoDBList) {
    dynamoDBList list = entry.asDynamoDBList();
    for (Iterator I = list.iterator(); i.hasNext(); ) {
        DynamoDBEntry listEntry = (DynamoDBEntry)i.next();
    }
}

You can also use entry.asString(), entry.asNumber(), etc. to convert to more primitive types.

Handling Data with the Document API

Document objects are used as the unit of transfer between your mobile app and Amazon DynamoDB. Each of the CRUD operations within the Document API either accepts or returns a Document object. First, create an Amazon DynamoDB client, then get a reference to the DynamoDB table:

DynamoDBClient client = new DynamoDBClient(awsCredentialProvider, config);
Table myTable = Table.loadTable(client, “MyTable”);

Once you have a reference to the table, you can use putItem(), getItem(), updateItem() or deleteItem() to perform CRUD (create, read, update, delete) operations. For example, if you know the key of the item that you want to retrieve, you can use this key to retrieve the document, obtain the text content, and assign it to an Android control:

Document retrievedDoc = myTable.getItem(new Primitive(“key”));
myTextView.setText(retrievedDoc.get(“stringField”).asString());

If the user has changed the text, you can update the document as follows:

retrievedDoc.set(“stringField”, myTextView.getText());
Document updatedDoc = myTable.updateItem(retrievedDoc);

You can also query for data using the Document API. For example, to find all Document objects where the Age field is greater than 5:

final Expression expression = new Expression();
expression.setExpressionStatement("Age > :age");
expression.withExpressionAttibuteValues(":age", new Primitive(5));
Search searchResult = table.scan(expression);
List<Document> documents = searchResult.getAllResults();

The table.scan() method performs a query across all fields in the table, which is probably not the most optimal method for querying the table. If you have a partition key called userId (which contains the user’s ID), then you can run queries across a single partition using the table.query() method:

final Expression expression = new Expression();
expression.setExpressionStatement("Tag = :tag");
expression.withExpressionAttibuteValues(":tag", new Primitive(“sports”));

Search searchResult = table.query(new Primitive(“myUser”), expression);
List<Document> documents = searchResult.getAllResults();

This method will have better performance because DynamoDB is scanning fewer records.

Document API limitations

The DynamoDB Document API does not currently support:

  1. Data types such as S3Link, Date, Calendar, etc.
  2. Batch operations.
  3. Conditional expressions.

The Document API is currently in beta and we would like to hear about the use cases you would like us to support. You can leave your feedback and issues on our forums and GitHub.

In the second part of this blog, we will describe how to integrate the Document API into a real Android app and provide a sample app that shows the Document API in action.

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.

 

 

Amazon Cognito User Pools supports federation with SAML.

Last year, we launched SAML federation support for Amazon Cognito Identity. This feature enables you to get temporary scoped AWS credentials in exchange for a SAML response. Amazon Cognito Identity supports an API-based approach that requires you to parse the SAML response from the SAML IdP (Identity Provider) and call the Amazon Cognito Identity API with a SAML response to get the AWS credentials.

With Amazon Cognito user pools, you can add user sign-up and sign-in to your mobile and web apps using a secure and scalable user directory. Now we are excited to announce that you can federate users from a SAML IdP with Amazon Cognito user pools, map these users to a user directory, and get standard authentication tokens from a user pool after the user authenticates with a SAML IdP. User pools support SAML 2.0 post-binding endpoints. This eliminates the need for client-side parsing of the SAML assertion response and the user pool directly receives the SAML response from your IdP through a user agent.

As part of the SAML federation feature, the user pool acts as a service provider (SP) on behalf of your application. The user pool becomes a single point of identity management for your application, and your application does not need to integrate with multiple SAML IdPs. You can add one or more SAML IdPs by using the Amazon Cognito console, where you can define attribute mapping and get started quickly.

Use the following steps to enable a SAML IdP for your mobile or web app with Amazon Cognito.

1. Set up the SAML IdP in Amazon Cognito User Pools
To set up a SAML IdP in Amazon Cognito User Pools, you need the metadata file or metadata endpoint URL from your SAML IdP. You can refer to your IdP’s documentation to find the metadata. For example, if you use Microsoft Active Directory Federation Service (AD FS), the metadata URL looks like: https://<yourservername>/FederationMetadata/2007-06/FederationMetadata.xml.

After you have the SAML IdP metadata, do the following:

  • Sign in to the Amazon Cognito console, choose Manage your User Pools, and then select Identity providers in the federation section.
  • If you don’t have a user pool, create one.
  • Select Identity Provider via SAML Federation.
  • Provide the metadata URL or upload the metadata file.
  • Provide a name. Optionally, provide a list of comma-separated identifiers to create the SAML provider.

 

 

If you have a public SAML IdP metadata endpoint, we recommend that you provide the metadata URL. This enables Amazon Cognito to automatically refresh metadata when it is near expiration. Make sure that you have SSL set up correctly for your metadata endpoint if you are using the metadata URL to set up the SAML provider.

2. Enable your App Client to allow federation from the new SAML IdP 

Next, you configure this SAML provider for an available app client in the Amazon Cognito console:

  • In the App integration section, select App client settings.
  • If you have already created app clients, they are displayed. If you don’t have an app client, create one in the App clients section under General Settings.
  • Find the name of the SAML IdP you set up earlier and select the corresponding check box for your app client.
  • Provide the Callback URL(s). This is a comma-separated list of URLs for your application, which Amazon Cognito is allowed to redirect to after successful authentication.
  • Provide the Sign out URL(s). This is a comma-separated list of URLs for your application, which Amazon Cognito is allowed to redirect to after successful sign out.
  • Select Allowed OAuth Flows. If you do not want to expose Amazon Cognito tokens to the user agent, select Authorization code grant flow. If you have a public client, select Implicit grant flow. For more information, see https://tools.ietf.org/html/rfc6749#section-4.1.  For this example, select both.
  • Select the allowed scopes for the token, which will be vended to the client. If you want your user to be able to call Amazon Cognito user level APIs (ChangePassword, UpdateUserAttributes, etc.) with the access token, select the ‘aws.cognito.signin.user.admin’ scope. If you want to issue an ID token for the user for the given app client, select the ‘openid’ scope. For this example, select all of the scopes.
  • Select the Attribute mapping section. These mappings map the claims from the SAML assertion from your SAML IdP to your user pool attributes. Make sure that you create a mapping for all the required attributes for your user pool.


3. Add Amazon Cognito as a relying party in your SAML identity provider

You are done setting up your user pool for your SAML IdP. If you have not created a domain already, create a domain for your user pool by using the Domain name tab in the Amazon Cognito console. Enable your user pool as a relying party in your SAML IdP. You need the following information:

  • The SAML 2.0 post-binding endpoint for your user pool will be : https://<domain_prefix>.auth.<region>.amazoncognito.com/saml2/idpresponse. You can find the domain prefix and region values in the Domain name tab. Please note that any SAML identity providers that you created in a user pool during the public beta before August 10, 2017 have redirect URLs of https://<domain_prefix>.auth.<region>.amazoncognito.com/login/redirect. These identity providers will continue to support the old redirect URL. But for future compatibility, please update the configuration in your SAML identity provider to accept both the old and new redirect URLs.
  • The URN for your user pool service provider will be : urn:amazon:cognito:sp:<user_pool_id>. You can find the user pool id in General settings tab.
  • Make sure that your SAML IdP populates NameID and any required attributes for your user pool in the SAML assertion. The NameID populated by your SAML IdP uniquely identifies your SAML federated user in the user pool. Use persistent identifier for NameID.

4. Get started with your application

You can get started by using the UI hosted by Amazon Cognito. Open following URL in your web browser:

https://<domain_prefix>.auth.<region>.amazoncognito.com/login?response_type=token&client_id=<app client id>&redirect_uri=<your redirect URI>

Your configured SAML IdP is displayed in this page. Clicking the SAML IdP takes you to the /authorize endpoint. This endpoint redirects you to the IdP. After you authenticate with the IdP, you are redirected back to your application’s callback URL.

5. IdP identifiers support

In common scenarios, your application can be used by multiple organizations. To redirect the user of your app to the SAML IdP of the organization the user belongs to, use IdP identifiers while setting up the SAML IdP in your user pool. Typically, these identifiers are the domain names used in the email addresses of users of the organization. When the users try to sign in with a SAML IdP, you can ask for their email address, extract the domain name, and pass it as idp_identifier to the /authorize endpoint. If the IdP identifier is associated with an IdP, Amazon Cognito automatically redirects the user to the corresponding IdP. The following is an example of an /authorize call with an idp_identifier parameter:

https://<domain_prefix>.auth.us-east-1.amazoncognito.com/authorize?idp_identifier=cognito.com&response_type=token&client_id=<app client id>&redirect_uri=<your redirect URI>

The SAML federation feature in Amazon Cognito User Pools helps you set up and integrate your apps with multiple SAML IdPs. When you are using the SAML federation feature, your app does not need to handle the type of SAML IdP it is interacting with. Amazon Cognito takes care of it on behalf of your application.

We welcome your feedback on this feature. For more information, see Creating and Managing User Pools in the Amazon Cognito Developer Guide. You can reach us by posting to the Amazon Cognito forums.

 

Deep Linking – Track and Engage Mobile App Users

You are about to enter the incredibly engaging and often confusing world of mobile deep linking. You’ll learn what deep linking is—the types of links, what deep linking can do, and why you should care—and walk through implementation details with examples.

What is Deep Linking?

Think of a deep link as a URL that takes you to a specific page or product within a website. Deep links are designed to send the mobile user to your app or content within your app, if installed. If not installed, links can launch a website or redirect a user to an app store to install the app.

There are three levels of deep linking: basic, deferred, and contextual. Each type is explained below.

Basic Deep Link

The basic form of deep linking is specifying a custom name for your app as a target for other mobile apps to launch your app and display specific content. This allows you to keep the user within the mobile app experience. If the user already has your app installed, this is cool. If your app isn’t installed, what happens?

The basic deep link works well when the app is installed but fails when it is not installed because the operating system does not know where to redirect.

Deferred Deep Link

A deferred deep link improves on the basic level. It informs the OS to redirect the user to a website or app store to download the app if the app is not installed. The website can display the content on a mobile browser if needed.  Or, if the user downloads and launches the app, the deep linked content is remembered. The user is presented with the intended content, just as if the user had the app installed in the first place.

Here’s an example flow that shows the value of deferred deep linking. The user is presented with three options. After selecting the circle object, the user is directed one of two ways: If APP 2, which is selling the object, is not installed on the user’s mobile device, the user is redirected to the app store. The user downloads and launches APP 2 and is then presented with, and can purchase, the discounted circle object that was originally selected in APP 1 as a promise. The discounted circle object content was deferred for the user until the user installed and launched APP 2. The user can now add the circle to the shopping cart with the applied discount, all within the native mobile app experience.

 

Deferred deep linking has the basic flow of launching an app to specific content but takes it a step further by enhancing the user experience. This helps acquire more users and improves the retention of existing users. It requires a little more effort in the implementation but handles most use cases for mobile user interaction and engagement.

Contextual Deep Link

The final stage is contextual deep linking. Contextual deep linking takes the basic and deferred links to a new level but looks exactly the same to the end user. With contextual, you are just adding valuable metrics (e.g., referrers, coupons, user attributes, and so on) to track every user interaction, from the user clicking the link to making a purchase in the mobile app. Let’s look at this interaction:

 

Contextual deep linking follows the same basic and deferred pattern but enables you to track the activity of your users throughout their mobile journey. In this case, contextual deep linking can carry information such as referrals, the pages within your app they were sent to, the promotional codes they use, the pages they visit within your app, etc. Access to this data can increase user conversion and app retention, all while giving your users a consistent, smooth, single-platform mobile experience.

What Does Deep Linking Do?

When a mobile app is configured for deep linking, it allows users to launch your mobile app directly (if installed on their device) to specific content within the app.  If the app is not installed, the user can be redirected to specific content on a website or directed to download the app in the app store. If the app is installed and launched, the original content is displayed in the mobile app. A deep link can also be set up to route specific content to a mobile browser where it makes sense.

How Does Deep Linking Work?

The app developer creates a unique name for his or her app and configures the app to handle redirection of an incoming link to a page, product, or announcement within the app. Deep links indicate to the OS how to handle these incoming links so that the result is seamless (no visual redirects) and users are taken directly to the intended endpoint. Each platform has a different implementation but the end user flow is the same.

What Does a Deep Link Look Like?

Each mobile platform and OS has its own implementation but they have similar patterns to a URL as explained earlier. The latest deep link integration for both iOS and Android looks like traditional URLs (for example, http://myapp.com/path/to/content). However, previous versions of iOS and Android used a URI like this: myapp.com://path/to/content.

In the implementation, apply deferred deep linking as a URL and use a URI as a fallback. This enables you to handle third-party app flows that only support the URI scheme and users running a previous version of the OS.

Let’s Get Started

First, look at the following chart. It shows platform-specific support for deep linking. It’s important to understand the terms and implementation details for each platform and OS version.

Platform Specific Deep Linking Integration Instructions

For all iOS applications, use the latest Apple universal links for deep links introduced with iOS 9.2. For versions earlier than iOS 9.2, use Custom URI Schemes.

To enable universal links for iOS, Apple requires that your has Associated Domains enabled in the Apple Developer Portal and in your Xcode project. In addition, you’ll need to upload and host a configuration file (apple-app-site-association) at the root of your web server (this could even be a static web hosting enabled S3 bucket).

Get Started by following these steps to integrate universal links into your iOS app:

  1. Enable Associated Domains for your App ID in the Apple Developer Portal.
  2. In your Xcode project, enable Associated Domains under App Target > Capabilities.
  3. In the Domains field, add your website domain appended to applinks: as shown here: applinks:domain.com.
  4. Add a restorationHandler function to your iOS project AppDelegate to handle the incoming links.
  5. Add the Apple apple-app-site-association JSON file (without the .json extension) to the ROOT of your secure web server. Use the domain you provided in step #3 (your website must be served using HTTPS).
  6. Launch the app so that it registers the domain.

Done.

You can test the universal link functionality by sending a link with the URL specified in associated domains to your email or SMS. Selecting the link opens the app. The app’s restorationHandler in the AppDelegate manages the link URL and any attributes.

Universal link caveats:

  • iOS remembers the user’s first choice when opening universal links. If the user taps the top-right breadcrumb to open the link in Safari, all further taps take the user to Safari, and not open within the app. The user can switch back to opening the app (instead of the browser) by choosing Open in the app banner within Safari.
  • Universal links only work for iOS 9 and later. Universal links in early versions of iOS 9 only work on the device; they do not work on the simulator.
  • For users who are running versions of iOS earlier than 9.0, tapping a universal link to your website opens the link in Safari.

For all Android apps as of API 6.0, use Android App Links. For API version 5 and earlier, use Android Chrome Intents.

The easiest way to implement Android App Links is to use App Links Assistant, introduced in Android Studio 2.3. The assistant is a step-by-step wizard for setting up Android App Links. The wizard walks you through the following.

Launch your Android Studio 2.3 project and select Tools > App Links Assistant.

A.   URL Mapping

  1. Select Open URL Mapping Editor button
  2. Select ‘+’ to add a new URL Mapping
  3. Provide a URL
  4. Provide a path
  5. Select OK

B.     Add code to your app’s activities to handle incoming links.

  1. Select the Select Activity button
  2. Highlight the activity
  3. Select Insert Code button

C.     Associate your mobile app and your web site with Digital Asset Links.

  1. Select Open Digital Asset Links File Generator button
  2. Provide your domain
  3. Select Signing config radio button
  4. Select Generate Digital Asset Links file
  5. Upload the assetlinks.json file to the location as shown
  6. Select Link and Verify button

You are done with Android deep linking integration instructions. Congratulations!

Contextual Deep Linking Analytics

Using the contextual deep linking approach, you can track your campaigns and funnels by sending custom events to Amazon Pinpoint. Here’s a high-level overview of how you can track your campaigns by storing each interaction as a custom event using Pinpoint.

  1. Launch the AWS Mobile Hub console.
  2. Create a project.
  3. Choose User Engagement.
  4. Download the iOS Swift project sample app.
  5. Follow the six previous steps to enable universal links for iOS.
  6. In your Xcode project, navigate to the restorationHandler function within your AppDelegate. Add the following snippet of code to send a custom event to Amazon Pinpoint when a universal link is selected. The sample code with hard-coded key/values. You capture these values from the incoming referring linked attributes.

Here’s what the custom event looks like in the Amazon Pinpoint console:

Deep Linking Terminology

Apple Universal Links – The latest version of deep linking for iOS, as of iOS 9.2.

Android App Links – The latest version of deep linking for Android as of version 6.

URI Scheme – The original deep linking format on iOS, before version iOS 9.2. A URI Scheme for deep linking looks something like appname://page/1234, where appname is your unique app name and page/1234 is the page content within the app that is installed on the user’s iOS device.

Android Intent with Chrome – A feature in Android that you use to launch an app directly from a webpage via an Android intent. This feature works in the Chrome for Android browser, version 18 and earlier.

Deferred Deep Links – A deep link that points to content inside a mobile app that is not yet installed. The link brings the user to the download page in the app store. After downloading the app, the user launches the app and is taken directly to the content within the app.

Conclusion

In nearly all categories, mobile app developers can benefit by implementing deep links into their own apps. The implementation process can be a bit involved but once you apply the platform-specific requirements, the benefits far outweigh the additional effort.

Happy linking everyone!

Web and Hybrid Mobile App Solution from AWS Mobile Hub and Ionic

AWS Mobile Hub and Ionic, an open source framework for building mobile apps, have teamed up to create an official Ionic starter project that demonstrates an end-to-end solution for hosting and building mobile web and hybrid applications on AWS.

In this blog post, we explain what the project is, describe key areas, highlight additional use cases, and then send you on your way to get started.

What is the official Ionic AWS starter project?

The Ionic team used the new Mobile Hub project export/import feature to build an official Ionic AWS starter project (Ionic blog | GitHub). The project demonstrates how quick and easy it is to deploy an end-to-end Ionic application on AWS using Mobile Hub.

The Ionic starter project is a sample mobile and web “todo task list” app based on a pre-configured AWS Mobile Hub project. After you import this exported Mobile Hub project from Ionic, Mobile Hub provisions the backend services. The Ionic project shows how to securely authenticate users with Amazon Cognito User Pools and receive AWS credentials. At that point, the user can read and write application data to Amazon DynamoDB and store user profile images to Amazon S3.

What is Ionic?

Ionic is an open source framework for building cross-platform hybrid mobile applications using web technologies like HTML, CSS, and JavaScript. Ionic is built on top of AngularJS and Apache Cordova. Ionic apps can be distributed through native app stores by using Apache Cordova API to call JavaScript functions that map to native code or plugins.

What is deployed on AWS?

Let’s look at the backend resources. After importing the exported project from Ionic, Mobile Hub creates a new project, and then enables and provisions the User Sign-in, NoSQL Database, User Data Storage, and App Content Delivery features. The Mobile Hub feature cards are curated common mobile use cases consisting of one or more AWS services. To learn more about these Mobile Hub features, click here.

To get started, download the mobile-hub-project.zip from GitHub and navigate to the Mobile Hub console. Click Import your project and drop the .zip file into the dialog box. Select Import Project. Mobile Hub creates the project and resources.

The purple cards indicate the enabled features, which were auto-generated by the Ionic imported project template.

Let’s explore the enabled backend features of your AWS Ionic Starter Project and see what they do.

User Sign-in: This feature creates an Amazon Cognito User Pool for identity management. The user pool allows your users to authenticate (sign-up and sign-in). After a user authenticates, they are provided a unique identifier by Amazon Cognito. That identity is used to generated temporary, limited-privilege AWS credentials to directly access your resources.. That identity is used when creating, editing, and deleting tasks within the app. Only the task that the authenticated user creates is available to the user. And… no more secret keys!

To view the configuration and a list of your users in the Amazon Cognito console, go to your Mobile Hub project, select resources, and then choose the direct link to your Amazon Cognito User Pools.

NoSQL Database: This creates a single Amazon DynamoDB table called “ionic-mobile-hub-tasks” for storing each task. Here’s what the data looks like (in the Amazon DynamoDB console) after creating a few tasks in the Ionic app. The userId is the Identity given to that user by Amazon Cognito.

To view the table data within the DynamoDB console, go to your Mobile Hub project, select resources, and then choose the direct link to your table under Amazon DynamoDB Tables.

User Data Storage: This created a single Amazon S3 bucket that is used to store files such as photos or other user content. When running the Ionic app on a device, users can click their account settings and change their profile picture, which stores the image in the S3 bucket.

App Content Delivery: This is the core of the Ionic web application. This feature created a single S3 bucket. In the S3 bucket, you’ll see some sample images along with the AWS SDK for JavaScript, aws-config.js, and a default index.html file. In addition, the S3 bucket is configured as a website to demonstrate the ability to host web content directly from your S3 bucket without having a web server. Because an Ionic application can be run either on a device as a native app or as a web app, the app can be hosted on an S3 static website.

Here’s a list of the bucket contents after enabling the App Content Delivery feature within Mobile Hub but before copying the web assets from your Ionic starter project.

In the Ionic starter project instructions, you copy the aws-config.js from here to your project to run the app locally. Instead of running your app locally using “$ionic serve” you just copy the web assets in your myApp/www/ to the root of your S3 bucket. To do this inside your Ionic project, run the following commands, substituting WEBSITE_BUCKET with the S3 content delivery bucket name that was created by the Mobile Hub project import.

npm run build
aws s3 cp --recursive ./www s3://WEBSITE_BUCKET

To learn more about setting up a static website on Amazon S3, see the Amazon S3 Developer Guide.

What have we built today?

The Ionic starter project provides a full end-to-end experience. Once configured, the app is quite diverse and is truly cross-platform. The same code base can be run locally as a web app in a browser, deployed to an iOS or Android device as a hybrid mobile app, or served from an S3 bucket for desktop and mobile browser users. The app showcases the ability to sign in from any device or browser and then sign in on another device: the user’s task list follows the sign-in because the data that is stored in Amazon DynamoDB is associated with that user.

Here’s a look at the interaction with the Ionic todo app from different platforms:

Running the web app locally and interacting in a desktop browser

 

Interacting with the web app served from Amazon S3, using a desktop browser

Ionic starter web app running from an installed app on an iOS device

 

The mobile web app being served from Amazon S3 on a mobile browser

 

Get Started

You’ll find the Ionic + AWS Mobile Hub Starter Project on GitHub. The README walks you through using the starter, installing the necessary CLIs, creating the project, running the app, and deploying the project’s web assets to the S3 bucket.

Additional Resources

AWS What’s New
Ionic Blog
Ionic on AWS

Sign Up and Confirm With Amazon Cognito User Pools Using C#

This post was authored by Tom Moore & Mike Morain, AWS Solutions Architects.

With Amazon Cognito, you can add user sign-up and sign-in to your mobile and web apps. You can also authenticate users through social identity providers such as Facebook, Twitter, or Amazon; with SAML identity solutions; or by using your own identity system.

Amazon Cognito user pools are for mobile and web app developers who want to handle user registration and sign-in directly in their apps. Previously, you needed to implement your own user directory to create user accounts, store user profiles, and implement password recovery flows to support user registration and sign-in.

This post follows on from the Basics – User Registration and Authentication post, and is intended to function as a companion to that post. The basics post walked through the process of setting up an Amazon Cognito user pool that can be accessed through an MVC 5 web site. This post walks through the process of developing a native Windows application to leverage the same app pool, by adding another app to the user pool for native Windows applications.

PREREQUISITES

 

COMPLETE THE WALKTHROUGH IN THE BASICS TUTORIAL

The previous blog post describes the steps to create your Amazon Cognito user pool and to get basic authentication working. You should complete all the steps in that post and ensure that you can successfully create accounts and authenticate to the user pool. This post assumes that you have access to the user pool created in that post, including the user pool ID and the identity pool ID, and that you are able to create a new client ID for the application to use.

VISUAL STUDIO

This blog post assumes that you are using Microsoft Visual Studio 2015 Community Edition. This edition is available for free from Microsoft at https://www.visualstudio.com/vs/community/.

NEW CLIENT ID

Each client that is authenticating to a user pool in Amazon Cognito requires a unique client ID.
To obtain a new client ID:

• Sign in to the AWS Management Console.
• Choose Amazon Cognito.
• Choose Manage your user pools.
• Choose the user pool you created in the previous post.
• In the lower left, choose Apps.
• In the list of applications, choose Add another App.

Give your application a name, select the following options, choose Create App, and then choose Save Changes.

After the application is created, note the client ID to use later.

PROJECT SETUP

Open Visual Studio 2015 and select the new project option.

From the built in templates, choose Classic Desktop application, and choose a project type of WPF Application. This option creates a blank WPF application to use as a starting point for this tutorial. Give the application a name and a location, and then click OK. Visual Studio now sets up the boilerplate code for your initial project.

After the application is created, run the application to ensure that the boilerplate code compiles correctly on your machine.

INSTALLING DEPENDENCIES

The first step to incorporate Amazon Cognito in your application is installing the necessary SDK components. You can use the built-in NuGet functionality to install these components.

Right-click in the Solution Explorer and then choose Manage NuGet Packages.

From the NuGet window, choose Browse, and in the search box type AWSSDK. The AWS SDK for .NET has many components, so you can install only the portions of the SDK that you need for your application. For this blog post we are working with Amazon Cognito to authenticate your application, so you can install only these components for now. In future posts, we will install additional components to access other AWS resources.

Note: All versions of the components used in this blog post are for version 3.x of the AWS SDK for .NET. Version 2 components are available in the NuGet repository for compatibility with older applications; however these should not be used. The following version numbers are correct as of the writing of this blog post.

Select and install the following NuGet packages:
• AWSSDK.Core (v3.3.7.1)
• AWSSDK.CognitoIdentity (v 3.3.1.1)
• AWSSDK.CognitoIdentityProvider (v3.3.2.3)

BUILDING THE INTERFACE

After you install the required components, you can build the Windows user interface for the application to interact with Amazon Cognito. In Visual Studio, add a second WPF window to act as the sign-up page. Right-click the project, choose Add, and then choose New Item. Choose WPF from the category of templates, and choose Windows (WPF) as the template. Name the new page SignUp.xaml and choose Add.

Open the MainWindow.xaml file and replace the default Grid XAML with the following:

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="1" Grid.Row="1">
            <TextBlock>User Name:</TextBlock>
            <TextBox Name="UserNameTextBox" />
            <TextBlock>Password:</TextBlock>
            <PasswordBox Name="PasswordTextBox" />
            <Button Name="LoginButton" Click="LoginButton_Click" Content="Login" />
        </StackPanel>
        <Button Name="SignUpButton" Grid.Column="2" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="SignUpButton_Click" Content="Sign Up" />
    </Grid>

This creates a basic login page with a button to launch a sign-up form. The login code is filled in later. Right-click the file and select View Code.

Open SignUp.xaml and replace the default Grid tag with the following XAML:

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="1" Grid.Row="1">
            <TextBlock>User Name:</TextBlock>
            <TextBox Name="UserNameTextBox" />
            <TextBlock>Password:</TextBlock>
            <PasswordBox Name="PasswordTextBox" />
            <TextBlock>Email:</TextBlock>
            <TextBox Name="EmailTextBox" />
            <Button Name="SignUpButton" Click="SignUpButton_Click" Content="Sign Up" />
            <TextBlock>Confirmation Code:</TextBlock>
            <TextBox Name="ConfirmatinTextBox" />
            <Button Name="ConfirmButton" Click="ConfirmButton_Click" Content="Confirm Email" />
        </StackPanel>
    </Grid>

INTEGRATING AMAZON COGNITO

ENABLE APPLICATION CONFIGURATION

Add a reference to the System.Configuration assembly into the project.

Open the App.Config file for the application and add the following code:

  <appSettings>
    <!-- AWS Cognito Identity Settings -->
    <add key="AWSRegion" value="{Your Region}" />
    <add key="CLIENT_ID" value="{Your Cognito Client ID}" />
    <add key="USERPOOL_ID" value="{Your User Pool ID}" />
    <add key="IDENITYPOOL_ID" value="{Your Identity Pool Id}" />
    <add key="IDENITY_PROVIDER" value="{Your Identity Provide}" />
  </appSettings>

Warning: The curly bracket sections must be replaced with the values from the user pool that you set up.

ENABLE NAVIGATION

Right-click MainWindow.xaml and choose View Code. In the code editor, make the following changes to the form code.

Add the following using statements to import the necessary AWS and supporting modules:

using Amazon;
using Amazon.Runtime;
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;
using System.Threading.Tasks;
using System.Configuration;

Add the following  items to the class as member variables.

private readonly AmazonCognitoIdentityProviderClient _client = new AmazonCognitoIdentityProviderClient();
private readonly string _clientId = ConfigurationManager.AppSettings["CLIENT_ID"];
private readonly string _poolId = ConfigurationManager.AppSettings["USERPOOL_ID"];

Add the following method to the form to handle opening the registration dialog.

private void SignUpButton_Click(object sender, RoutedEventArgs e)
{
       SignUp signUpDlg = new SignUp(_client);
signUpDlg.ShowDialog();
}

The code provides the ability to launch your sign-up page in the application, which enables you to create new accounts in Amazon Cognito.

IMPLEMENT SIGN-UP

The sign-up page and related code are used to enable a client application to create user accounts within the Amazon Cognito identity provider. This assumes that you want all user accounts to be created from the end-user application. If you do not intend for the application to create users, then you should remove the sign-up page from the application, along with the code to launch the sign-up page.

The process of creating users is performed by Amazon Cognito within your AWS account. All of the rules governing accounts are maintained in the Amazon Cognito user pool configuration. The following code shows basic user creation. You can modify it to suit your business processes; for example, if you require more options for user creation.

Right-click the SignUp.xaml page and choose View Code to edit the sign-up code.

Update the boilerplate code for the SignUp class with the following:

private readonly string _clientId = ConfigurationManager.AppSettings["CLIENT_ID"];
private readonly string _poolId = ConfigurationManager.AppSettings["USERPOOL_ID"];
private AmazonCognitoIdentityProviderClient _client;

public SignUp(AmazonCognitoIdentityProviderClient client)
{
        InitializeComponent();

        _client = client;
}

This enables the application to pass the Amazon Cognito client to the Signup.xaml form, and retrieves the client ID, which is used for the sign-up process.

Add the following code to the SignUp.xaml form.

private async void SignUpButton_Click(object sender, RoutedEventArgs e)
{
     try
     {
         SignUpRequest signUpRequest = new SignUpRequest()
         {
               ClientId = _clientId,
               Password = PasswordTextBox.Password,
               Username = UserNameTextBox.Text
         };
         AttributeType emailAttribute = new AttributeType()
         {
              Name = "email",
              Value = EmailTextBox.Text
         };
         signUpRequest.UserAttributes.Add(emailAttribute);

         var signUpResult = await _client.SignUpAsync(signUpRequest);
     }
     catch (Exception ex)
     {
        string message = ex.Message;
        MessageBox.Show(message, "Sign Up Error");
     }
}

This code implements a handler for the sign-up button. The sign-up button handles the process of Amazon Cognito creating an account from the client. If your user pool requires additional attributes for the user, you include them here along with the email attribute in the preceding example.

After the user is created in Amazon Cognito, a confirmation email is sent to the specified email address, along with a confirmation code. The user uses that confirmation code to complete the sign-up process.

Add the following code to the sign-up form to enable account confirmation and complete the sign up process.

private async void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
     try
     {
          Amazon.CognitoIdentityProvider.Model.ConfirmSignUpRequest confirmRequest = new ConfirmSignUpRequest()
          {
               Username = UserNameTextBox.Text,
               ClientId = _clientId,
               ConfirmationCode = ConfirmationTextBox.Text
          };

          var confirmResult = await _client.ConfirmSignUpAsync(confirmRequest);
     }
     catch (Exception ex)
     {
           string message = ex.Message;
           MessageBox.Show(message, "Sign Up Error");
      }
}

The user receives the confirmation code, types it into the Confirmation text box, and clicks the Confirm button. This completes the registration process.

IMPLEMENT SIGN-IN

The final step is to implement the sign-in process for the mobile application. Right-click the MainWindow.xaml file and choose View Code to edit the code for the main dialog box in the application.

Add the following code to your application:

private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
     bool loggedIn = await CheckPasswordAsync(UserNameTextBox.Text, PasswordTextBox.Password);
}

private async Task<bool> CheckPasswordAsync(string userName, string password)
{
     try
     {
          var authReq = new AdminInitiateAuthRequest()
          {
               UserPoolId = _poolId,
               ClientId = _clientId,
               AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH
          };
          authReq.AuthParameters.Add("USERNAME", userName);
          authReq.AuthParameters.Add("PASSWORD", password);

          AdminInitiateAuthResponse authResp = await _client.AdminInitiateAuthAsync(authReq);

          return true;
     }
     catch (Exception ex)
     {
           return false;
     }
}

The preceding code enables the user to sign in with Amazon Cognito.

NEXT STEPS

Completion of this walkthrough enables you to create and authenticate against those accounts within your application. The next steps are to allow the user to interact with other AWS resources within your account. These interactions will be covered in subsequent posts.

WHAT DOES IT COST?

The only service used in this walkthrough is Amazon Cognito. This service is free for the first 50,000 monthly active users. Accessing other AWS resources may incur charges.

CONCLUSIONS

This post extended the previous post by using the user pool you created and enabling a Windows native client to sign up, confirm, and authenticate. After you complete this process, you can extend your application to use other AWS capabilities.

Questions or Comments?

Reach out to us via the AWS Mobile Development Forum.

Export, Import, and Clone AWS Mobile Hub Projects

by Dennis Hills | on | Permalink | Comments |  Share

This post was authored by Bharath Kumar, Sr. Product Manager, AWS Mobile.

AWS Mobile Hub now supports exporting and importing the configuration of an AWS Mobile Hub project from the Mobile Hub console with a few clicks. You can import previously exported Mobile Hub projects from any AWS account or import your own exported Mobile Hub projects. You can create just the right project and clone it as a backup or as a template for building out other projects. These exported projects can be shared with other teams or even across AWS accounts. Importing a project creates an identical isolated stack of AWS resources that provides an independent consistent development and testing environment.

Developers will find the export/import feature helpful: where multiple developers, working in parallel, need repeatable mobile backend deployments for testing and debugging; in open source sharing contexts; and for getting-started projects, short-cutting tutorial setup, or as a working template to build from.

How Does It Work? For exporting, you create a project, enable features, and configure resources as you normally would. You then select the project card and select export. The export is a zipped YAML file that can be imported into your own account as another project. You can also share the file with another user or account for the user to import.

Importing a project requires you to log in to the Mobile Hub console, choose the Import your project button, and drop the previously exported zipped YAML file into the import modal. On importing a project, Mobile Hub creates a new project and begins creating the resources defined by the imported YAML.

We’ll show you how easy it is to export, import, and clone a Mobile Hub project.

Exporting a project

You can export a project by selecting the export button on your project card. Exporting a project creates a zipped YAML file. The YAML file represents all the configured backend resources and features enabled in your project.

Importing a project

To import a project, select Import your project in the project list page and drag and drop the exported zipped YAML file into the Import project modal. After you select the zipped Mobile Hub project file for importing, the project name is pre-populated according to the name of the zip file. You can change the name of the project and select the region where you want resources to be created.

Importing the zipped YAML file into the AWS Mobile Hub console creates a new project and begins provisioning the backend resources and features defined in the YAML file.

Cloning a project

Cloning a project combines export and import into a single step. You can only clone your own projects. Cloning a project creates a project with the same provisioned backend services and  features as the project you cloned it from.

Limitations of Cloning and Importing Projects

  1. Importing a NoSQL feature requires unique DynamoDB table names.
  2. Any exported project credentials (always encrypted in the export) can only be imported into the same account from where they were exported from.
  3. Existing AWS resources that were added to a project, such as a legacy Cloud Logic API function or Push Notifications, can only be imported into the same AWS account where they were created.

Note about legacy Cloud Logic: Export, import, and cloning are not supported for projects that include the legacy Cloud Logic feature (indicated by a type LEGACY in the Cloud Logic feature as shown below). Legacy Cloud Logic refers to any enabled Cloud Logic features prior to the integration of Amazon API Gateway into Cloud Logic on November 9, 2016.

Supported import and cloning feature reference table:

AWS Mobile Hub Feature Clone Import
CAN A PROJECT CONTAINING THIS FEATURE BE CLONED WITIHIN THE SAME AWS ACCOUNT? CAN A PROJECT CONTAINING THIS FEATURE BE IMPORTED INTO A DIFFERENT AWS ACCOUNT?
User Sign-In  Yes  Yes
No SQL Database  Yes  Yes
Cloud Logic  Yes  Yes, if Cloud Logic API was created by Mobile Hub and not imported.
User Data Storage  Yes  Yes
App Content Delivery  Yes  Yes
Connectors  Yes  No
Push Notifications  Yes  No
User Engagement  Yes  No

To learn more about the AWS Mobile Hub export, import, and clone feature, see the AWS Mobile Hub Developer Guide.

Use C# To Register and Authenticate with Amazon Cognito User Pools

This post was authored by Tom Moore & Mike Morain, AWS Solutions Architects.

You can use Amazon Cognito to add user sign-up and sign-in to your mobile and web apps. You can also authenticate users through social identity providers such as Facebook, Twitter, or Amazon; with SAML identity solutions; or by using your own identity system.

Amazon Cognito user pools enable you to handle user registration and sign-in directly in your app.Without user pools, you needed to implement your own user directory to create user accounts, store user profiles, and implement password recovery flows to support user registration and sign-in.

This post is intended for developers working in C# who want to integrate backend web applications with Amazon Cognito. It provides an overview of basic authentication integration with user pools. We demonstrate how to do this with C# and the .NET stack, but you can apply these ideas by using our other SDKs too.

PREREQUISITES

IAM User

To integrate with the Amazon Cognito APIs, you must have an AWS user with programmatic access. If you need information on how to get this access, see Creating IAM Users in the AWS Identity and Access Management User Guide. If you already have an account that has access to the credentials, read on.

Deploying ASP.NET on AWS

While there are many tools that leverage the C# .NET platform on AWS, one of the fastest ways to get started is to deploy the application with AWS Elastic Beanstalk. For more information, see the How to Deploy a .NET Sample Application Using AWS Elastic Beanstalk tutorial in the AWS Elastic Beanstalk Developer Guide.

AWS Toolkit for Visual Studio

For this tutorial, we recommend the AWS Toolkit for Visual Studio. It enables you to access and manage AWS resources inside of Visual Studio. It also supports credential management and injection to ease the development workflow. For more information, see Setting Up the Toolkit for Visual Studio in the AWS Toolkit for Visual Studio User Guide. If you’ve already got your development environment set up, feel free to skip ahead.

Note: The AWS Toolkit for Visual Studio is great for storing credentials during the development cycle, but cannot be used for storing credentials in a production application. For more information on how to secure your credentials in a production environment, see Using Credentials in an Application in the AWS SDK for .NET Developer Guide.

Setting up Amazon Cognito

Set up the User Pool

In Amazon Cognito, a user pool represents a set of identities for users of an application. To integrate with Amazon Cognito, you must first set up a user pool where information about your app’s users is stored. Since this is a one-time setup for the purposes of this demo, we demonstrate this using the AWS Management Console. You can also use the AWS CLI or an AWS SDK. For more information, see Using the Console to Create a New User Pool in the Amazon Cognito Developer Guide.

While setting up the user pool, you also define an application that provides programmatic access to each user pool. This is shown next. During app creation, it is important to note the user pool ID and app client ID. You use these later when integrating this user pool and application with the Amazon Cognito identity pool. For more information, see Specifying User Pool App Settings in the Amazon Cognito Developer Guide.

Ensure that the Generate client secret box is cleared. Since you are authenticating with your AWS credentials, no user secret is required.

Figure 1: Don’t generate a client secret, since you are authenticating with credentials

It is also important to select the Enable sign-in API for server-based authentication (ADMIN_NO_SRP_AUTH) box for this integration. For client-side applications, Amazon Cognito uses the Secure Remote Password (SRP) protocol, which allows for secure password entry and transmission from code running on the client device. However, since the C# code for this tutorial runs on a trusted and secured backend server, you don’t need to implement SRP. Selecting this box allows you to use these secure API endpoints from this application.


Figure 2: Enable ADMIN_NO_SRP_AUTH

Overview of C# Configuration and Code

The code snippets in this document were built into a default MVC 5 boilerplate application bootstrapped from the Visual Studio template wizard. Because the purpose of this document is to demonstrate basic integration functionality for Amazon Cognito in C#, the glue code required to integrate with Microsoft’s Open Web Interface for .NET (OWIN)[MS1]  authentication mechanisms are outside the scope of this document, and may be covered in a future blog post.

Web.CONFIG SETUP

The required configuration elements are outlined in the following Web.config excerpt:

<appSettings>
    . . .
    <!-- AWS Cognito Identity Settings -->
    <add key="AWSRegion" value="eu-west-1" />
    <add key="CLIENT_ID" value="XXXXXXXXXXXXXXXXXXXXXXXXXX" />
    <add key="USERPOOL_ID" value="REGION_XXXXXXXXX" />
    <add key="IDENITYPOOL_ID" value="REGION:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX" />
    <add key="IDENITY_PROVIDER" value="cognito-idp.REGION.amazonaws.com/" />
  </appSettings>

Figure 3: Required Web.config settings

The AWSRegion field should contain the standard formatted AWS Region name where the Amazon Cognito setup was performed. The CLIENT_ID is the app client ID from the Amazon Cognito user pool. The USERPOOL_ID and IDENTITYPOOL_ID are the user pool ID and identity pool ID that you set up in the prerequisites section. The IDENTITY_PROVIDER setting should point to the endpoint for the specified region (replace REGION in the preceding snippet with the AWS Region).

User Registration and Confirmation

The first thing to do is instantiate the Amazon Cognito identity provider client, as seen next. You also reference some of the configuration variables for easy access in the functions later on.

. . .
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;

    public class CognitoUserStore : IUserStore<CognitoUser>, 
                                    IUserLockoutStore<CognitoUser, string>, 
                                    IUserTwoFactorStore<CognitoUser, string>
    {
        private readonly AmazonCognitoIdentityProviderClient _client = 
            new AmazonCognitoIdentityProviderClient();
        private readonly string _clientId = ConfigurationManager.AppSettings["CLIENT_ID"];
        private readonly string _poolId = ConfigurationManager.AppSettings["USERPOOL_ID"];

        . . . 
    }

Figure 4: Instantiating the AmazonCognitoIdentityProviderClient

Next, create a standard object to store basic user information for a user stored in Amazon Cognito.

public class CognitoUser : IdentityUser
    {
        public string Password { get; set; }
        public UserStatusType Status { get; set; }
    }

Figure 5: Basic user object.

After you create the client object in _client, create a function to call the SignUpAsync, accepting the basic user object. This function then calls the Amazon Cognito API to register the user.

. . .
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;

    public class CognitoUserStore : IUserStore<CognitoUser>, 
                                    IUserLockoutStore<CognitoUser, string>, 
                                    IUserTwoFactorStore<CognitoUser, string>
    {
        . . . 

        public Task CreateAsync(CognitoUser user)
        {
            // Register the user using Cognito
            var signUpRequest = new SignUpRequest
            {
                ClientId = ConfigurationManager.AppSettings["CLIENT_ID"],
                Password = user.Password,
                Username = user.Email,

            };

            var emailAttribute = new AttributeType
            {
                Name = "email",
                Value = user.Email
            };
            signUpRequest.UserAttributes.Add(emailAttribute);

            return _client.SignUpAsync(signUpRequest);
        }
    }

Figure 6: Create a user identity with SignUpAsync()

For this tutorial, you confirm the user account manually. User confirmation and email verification will be covered in a future post. To confirm the user manually, sign in to the AWS Management Console and navigate to your user pool for your sample application. After you call the CreateAsync function with a valid user object, you should see the user in your pool. Choose the user ID, and on the detail page, click Confirm user.

Figure 7: Manual confirmation of the user.

USER Authentication

After creating and confirming the user, implement user authentication by creating a function to check the user’s credentials. Call the AdminInitiateAuthAsync function on the AmazonCognitoIdentityProviderClient.

. . .
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;

    public class CognitoUserManager : UserManager<CognitoUser>
    {

        private readonly AmazonCognitoIdentityProviderClient _client = 
            new AmazonCognitoIdentityProviderClient();
        private readonly string _clientId = ConfigurationManager.AppSettings["CLIENT_ID"];
        private readonly string _poolId = ConfigurationManager.AppSettings["USERPOOL_ID"];

        public CognitoUserManager(IUserStore<CognitoUser> store)
            : base(store)
        {
        }

	 . . .

        public override Task<bool> CheckPasswordAsync(CognitoUser user, string password)
        {
            return CheckPasswordAsync(user.UserName, password);
        }

        private async Task<bool> CheckPasswordAsync(string userName, string password)
        {
            try
            {
                var authReq = new AdminInitiateAuthRequest
                {
                    UserPoolId = ConfigurationManager.AppSettings["USERPOOL_ID"],
                    ClientId = ConfigurationManager.AppSettings["CLIENT_ID"],
                    AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH
                };
                authReq.AuthParameters.Add("USERNAME", userName);
                authReq.AuthParameters.Add("PASSWORD", password);

                AdminInitiateAuthResponse authResp = await _client.AdminInitiateAuthAsync(authReq);

                return true;
            }
            catch
            {
                return false;
            }
        }
    . . .
    }

Figure 9: Authenticating credentials with AdminInitiateAuthAsync()

And that’s it! Your C# application now integrates basic user creation and authentication with the Amazon Cognito platform.

Conclusion

In this post, we went through an overview of basic authentication integration with Amazon Cognito user pools in C#. After setting up the user pool, we walked through code for a basic user sign-up and authorization flow.

Please post your questions and feedback to the .NET Development Forum.