Category: AWS Mobile


Encrypting an Amazon S3 object on the client side with AWS KMS and the AWS Mobile SDK for Android

by Karthik Saligrama | on | in AWS Mobile, S3 | | Comments

Starting with the AWS Mobile SDK for Android version 2.4.0, you have two options to encrypt client-side objects before sending them to Amazon S3: an AWS Key Management Service (AWS KMS) customer master key (CMK) or a client-side master key.

 

Customer master key

 

When using an AWS KMS customer master key (CMK) for client-side data encryption, you provide only a CMK ID. The AWS Mobile SDK for Android sends a request to AWS KMS for a key to encrypt your data. There is no requirement to provide encryption keys to the Amazon S3 encryption client.

While uploading, the data in the object is encrypted and the cipher blob version of the encryption key that is returned from KMS is stored in the object metadata.

When the client calls Amazon S3 to download the object and its metadata, the client uses the cipher blob key to get the plaintext key to decrypt the entire S3 object.

The following example shows how to set up Amazon S3 client-side encryption with a CMK on an Android device using the AWS Mobile SDK for Android.

 

Initialize KMSEncryptionMaterialsProvider

 

final KMSEncryptionMaterialsProvider materialProvider = new KMSEncryptionMaterialsProvider(<kmsKey>); 
final CryptoConfiguration cryptoConfiguration = new CryptoConfiguration()
                                                      .withAwsKmsRegion(Region
                                                                   .getRegion(Regions.US_EAST_1));
final AmazonS3 s3Client = new AmazonS3EncryptionClient(<credentialProvider>, 
                                            materialProvider, 
                                            cryptoConfiguration);
s3Client.setRegion(Region.getRegion(Regions.US_EAST_1));

Uploading

To upload an object to Amazon S3, use the AmazonS3EncryptionClient you initialized, and then use either PutObjectRequest or TransferUtility.

Using PutObjectRequest
final PutObjectRequest putObjectRequest = new PutObjectRequest(<bucketName>, <key>, <file>);
final PutObjectResult putObjectResult = s3Client.PutObject(putObjectRequest);
Using TransferUtility
final TransferUtility transferUtility = new TransferUtility(s3Client, <context>); 
final TransferObserver transferObserver =  transferUtility
                                                  .upload(<bucketName>, <key>, <file>);

Downloading

To download an object from Amazon S3, use the AmazonS3EncryptionClient you initialized earlier, and then use either GetObjectRequest or TransferUtility.

Using GetObjectRequest
final InputStream inputStream = s3Client.getObject(<bucketName>, <key>).getObjectContent();
Using TransferUtility:
final File tempDownloadFile = temp.newFile();
final TransferObserver observer = transferUtility
                                       .download(<bucketName>, <key>, <tempDownloadFile>);

Client-side master Key

Your client-side master keys and your unencrypted data are never sent to AWS. It is important that you safely manage your encryption keys. If you lose them, you won’t be able to decrypt your data.

If you want to use your own custom master key, use the following code to create a material provider.

final EncryptionMaterials encryptionMaterials = new EncryptionMaterials(<keypair>);
final AmazonS3 s3Client = new AmazonS3EncryptionClient(<credentialProvider>, encryptionMaterials);

As always you can post your questions and feedback to our GitHub repo or to our AWS Forums.

 

Targeted push notifications and campaign management using Amazon Pinpoint and React Native

by Richard Threlkeld | on | in AWS Mobile, Lambda | | Comments

This post was authored by Michael Labieniec, AWS Solutions Architect

Amazon Pinpoint makes it easy to run targeted campaigns to drive user engagement with mobile apps. Using Amazon Pinpoint you can understand user behavior, determine which users to engage with your campaigns, determine which messages to send, schedule the best time to deliver the messages, and then track the results of your campaign. Building cross-platform mobile apps and engaging with users across these platforms can be challenging; it requires you to maintain multiple code bases to take advantage of native features using the AWS Mobile SDK.

React Native enables you to create cross-platform mobile apps while utilizing native features. By building custom native modules, you can interact with the native AWS Mobile SDK generated by AWS Mobile Hub. This means that you maintain a single code base, while customizing the look and feel per platform within React Native. In this example, we will show how to build a native module for the Android platform. The same concepts can be applied to iOS by building a custom module and using the Mobile Hub-generated package.

In this tutorial, you generate a Mobile Hub app that uses an unauthenticated Amazon Cognito identity pool and interacts with API Gateway and AWS Lambda. This app allows you to purchase round trip tickets to your favorite planet. The app generates monetization events using the native AWS Mobile SDK. It then creates custom user attributes for Amazon Pinpoint so you can engage with users based on their planet interest, traveled to destination, and weather preference. To add user authentication along with features such as registration and MFA, consider using the Amazon Cognito User Pools functionality, which you can enable in Mobile Hub.

Requirements

Clone the completed sample app from Github and use the files within this repository as reference when creating your app.

git clone https://github.com/awslabs/aws-pinpoint-sample

Once you have node.js and npm, you can get started by running the following commands from the terminal:

npm install -g react-native-cli
react-native init PinpointSample
cd PinpointSample

NOTE: If you name your project something other than “PinpointSample”, you will need to find/replace the  references in the sample code with your new project name.

Creating the API for your cross-platform app

Go to the AWS Mobile Hub console and click Create new mobile project. In this example for this tutorial, the app name is PinpointSample. Enter the name then click “Create Project”. In the list of features, choose Cloud Logic and then choose Create new API. Give the API a name PinpointSampleApi and a description, leave the defaults, and choose Create API. This API will simply return back whatever you send to it in the request body. You will use this API later in this tutorial to simulate requesting weather information for specific planets.

CREATE_IN_PROGRESS appears while the APIs are being created. When the status is CREATE_COMPLETE, choose “Configure more features”.

image005

Getting a GCM Sender ID and API Key

To send push notifications to Android devices, you need Google Cloud Messaging keys. To create a new Sender ID and API Key, go to https://firebase.google.com.

  • Choose an existing project or create a new project.
  • Click Add (another) app and select Android

Type your package name from the generated React Native app. In this example, it’s com.pinpointsample. Then click Add App. Click Continue and then Finish. Note, you don’t need the google.json file.

Click the menu icon to the right of your new app’s name and then choose Manage Settings. Choose the CLOUD MESSAGING tab. Copy the Sender ID and Legacy Server Key (this is the API Key).

Enabling User Engagement

In the AWS Mobile Hub console, choose User Engagement and then choose Enable engagement and select Android

  • In Sender ID, add the Sender ID from the previous procedure.
  • In API Key, add the Server Key from the previous procedure.

Click Save changes then choose Integrate with your app. Next choose the Android tab, and then choose Download package.

image009

Find the directory where you created your project earlier with the React Native CLI. Inside that directory, extract the amazonaws folder from the Mobile Hub package archive you downloaded from Mobile Hub to android/app/src/main/java/com/amazonaws. Overwrite the existing directory (if it exists).

image010

Creating the React Native Android Module

Open projectname/android/app/build.gradle with a text editor and add the following dependencies. The Google Play library is required to use push notifications. The included badge library places a badge next to your push notifications.

dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
    compile "com.android.support:appcompat-v7:23.0.1"
    compile 'com.android.support:support-v4:23.1.0'
    compile "com.facebook.react:react-native:+"  // From node_modules
    compile "me.leolin:ShortcutBadger:1.1.4@aar"
    compile 'com.amazonaws:aws-android-sdk-core:2.3.9'
    compile('com.amazonaws:aws-android-sdk-pinpoint:2.3.9')
    compile('com.amazonaws:aws-android-sdk-apigateway-core:2.3.9')
    compile 'com.google.android.gms:play-services-gcm:7.8.0'
    compile 'com.google.code.gson:gson:2.7'
}

Create 3 new files in the android/app/src/main/java/com/pinpointsample package folder. Copy the contents of the files from the corresponding sample app repository files.

  • AWSMobileHubModule.java
  • AWSMobileHubPackage.java
  • AWSPushListenerService.java

Next, update your android/app/src/main/AndroidManifest.xml. Copy the contents from the sample app repository. If you did not use the example package name of com.pinpointsample, be sure to update the package names in the manifest file to your package name.

Note: The package names must match your application package name.

In the android/app/src/main/com/amazonaws/mobile/AWSConfiguration.java file, remove the “final” from all variables. These variables will be updateable from the JavaScript interface.

Note: If you update your Mobile Hub app in the future, you mustoverwrite the com.amazonaws.mobile package folder and will need to perform this step again if you want to be able to configure the variables from javascript.

Finally, modify the MainApplication.java file to load your new package. Add import com.pinpointsample.AWSMobileHubPackage; to the imports section of the class, then update the getPackages() method to include the module:

@Override
    protected List getPackages() {
      return Arrays.asList(
          new MainReactPackage(),
          new AWSMobileHubPackage()
      );
    }

Add your configuration to the constructor method in by copying the contents of the index.android.js from the sample code into your projects index.android.js. The values can be copied from your Mobile Hub generated AWSConfiguration.java file class (where you previously removed the “final” statement).

Finally, create a AWSMobileHub.js file in your projects root directory. this is the main interface that communicates with our native module. Copy the contents from the completed sample app repository file.

Note: the name of the module corresponds directly to the getName property inside the java module code getName() method.

Finally, enable the gradle daemon to speed up builds; run this command from your terminal on your Mac or Linux computer.

touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties

Now, run the app either on a device (push notifications may not work on the Android Emulator). From your root project run the following command:

react-native run-android
adb logcat

image011

The following information is logged to adb logcat:

Note: use the logcat.sh script in the sample app repository to automatically filter your adb logs with ./logcat.sh (on mac/linux) or just “logcat” on windows.

  • AWSMobileClient: AWS Mobile Client is OK – This means the AWS Mobile SDK was initiated
  • EventRecorder: Successful submission of 1 events – These events are being submitted to Pinpoint
  • TargetingClient: EndpointProfile – These are Amazon Pinpoint events

Within the app, when you choose the Request Weather button, you see a request to Amazon API Gateway. This request calls an AWS Lambda function, which simply returns the request. The app echoes the query parameter that was sent; in this case, the weather for the selected planet.

The API Gateway call can be used to send any request to API Gateway by passing in the method, endpoint, request body, and query params (see comments in the sample code). This call uses the Amazon Cognito identity, which in this example is an unauthenticated user. You can instead use a login system with an authenticated role and the SDK manages that for you. This call also sets custom attributes for the Weather Requested attribute so that you can engage with specific users that requested weather for a specific planet by creating a custom user segment within Amazon Pinpoint.

Next, choose Planet Trip, {COST}. The event echoes out in the adb log, which creates a monetization event using the AWS Mobile SDK. This event also updates custom attributes about this user under the Traveled To attribute, which enables you to engage with users who have traveled to this specific planet.

Enabling Campaign Management with Amazon Pinpoint

Next we are going to create user segments for each of the planet attributes users are interested in traveling to. Then we will create a campaign that targets these specific users based on their interests.

Go to the Amazon Pinpoint console and click on your app (if you used “PinpointSample” as the name of your Mobile Hub app, your Pinpoint app should be called “pinpointsample_MobileHub”), choose Segments, and then choose New Segment. Name your segment after a planet that you selected within the app; for example, “Earth People” if, in the app, you purchased a trip to Earth by clicking “Planet Trip”. Choose the + button under Custom Attributes, choose Planet and then choose Earth. This enables you to engage with all users that picked Earth in the app. You can also specify a usage metric; for example, Used within the last 30 days. The user count goes to 1 and shows 100%. This indicates that all current users are interested in this planet.

image013

Next, choose Campaigns, and then choose Create Campaign. Choose the segment that you created in the previous step by selecting Use a previously defined segment. For this example, the segment is called “Earth People”.

image014

The Segment estimate should be 1 total user. If the Segment estimate is 0, give it some time, refresh the app, and refresh the console. Be sure you see the Endpoint updated successfully event in the logcat log. If you are only running the app on the Android Emulator, try running it on a device instead.

Click Next step, choose Message and type a message. For example, in Title, type “Earth is Awesome”, and in Message, type “Travel to Earth now the weather is great!”

image015

Choose Next step.

image016

In the Advanced section, choose Immediate, and then choose Review and Launch. Choose Launch Campaign and return to the app running on your device. If the app is active the alert popup will display with your message. If your app is minimized, your notification appears in the top area of the screen with any other notifications. You can also see the update in the Amazon Pinpoint console. Tapping your notification will open your app. This behavior can be customized when you create the campaign within Amazon Pinpoint.

image017

Next, in the app, choose another planet. If your terminal is open, you should see a Endpoint updated successfully event display. Go back to the Amazon Pinpoint console. Choose Copy to new campaign. Choose Segment, choose Create a New Segment, and then choose Custom.

In “Customer Attributes” choose Planet and then choose the planet name you chose in the previous step. Repeat the preceding steps to send push notifications to this custom segment.

The custom attributes (attribute,value) can be changed in the index.android.js file’s _customAttributes function. The native module takes a simple comma delimited string as its argument for custom attributes, as follows.

  • @param {String} Attribute name i.e. “Interest”
  • @param {String} Attribute values i.e. “Pizza, Sushi”

You should also now see monetization events if you choose the Planet Trip, $200.00 button in the app. The monetization and usage data is populated in the Amazon Pinpoint console in near real time. When you choose the Planet Trip button in the app, the event is sent via Google Play monetization builder in the native AWS Mobile SDK. You can customize the values in index.android.js method via JavaScript. You can also customize and send more parameters by modifying the AWSMobileHubModule.java file to send details like Transaction ID. You simply need to update the generateMonetizationEvent method appropriately.

Questions or Comments?
Reach out to us on the AWS Mobile Development Forum.

Source Code on GitHub
github.com/awslabs/aws-pinpoint-sample

AWS Mobile SDK for iOS version 2.5.0 – Improvements and changes to Swift support

by Karthik Saligrama | on | in AWS Mobile | | Comments

What

Version 2.5.0 of the AWS Mobile SDK for iOS introduces better compatibility for a Swift 3 migration.

This blog walks through improvements and breaking changes with this SDK release that are relevant for Swift developers.

When you open your legacy Swift 2.x project with Xcode 8.0 for the first time, you will be prompted by the Swift Migration Assistant to migrate to Swift 3. The following changes have been made to the AWS Mobile SDK for iOS to better support the migration.

Compatibility Improvements

AWS Mobile SDK for iOS version 2.5.0 now has better support for Auto-Completion, added generics, and improved name translation for AWSTask so that it handles the Xcode 8 Swift Migration Assistant gracefully and predictably.

Here are some examples of the changes that will improve the migration to Swift 3:

  •  Added more generics support for public APIs. For example, in Amazon Cognito Sync, dataset.getAllRecords() now returns an array of type AWSCognitoRecord instead of an array without a type.
  • Improved name translation for AWSTask continueWithSuccessBlock and continueWithBlock. This enables Xcode to distinguish these methods and it avoids returning an ambiguous use of the continue error message. To illustrate, The following is an asynchronous call to list Amazon DynamoDB tables:

Prior to iOS SDK 2.5.0

let dynamoDB = AWSDynamoDB.defaultDynamoDB()

let listTableInput = AWSDynamoDBListTablesInput()

dynamoDB.listTables(listTableInput).continueWithBlock{ (task: AWSTask?) -> AnyObject? in
    if let error = task.error {
       print("Error occurred: \(error)")
       return nil
    }

    let listTablesOutput = task.result as  AWSDynamoDBListTablesOutput
    for tableName in listTablesOutput.tableNames {
        print("\(tableName)")
    }
    return nil
}

After iOS SDK 2.5.0

let dynamoDB = AWSDynamoDB.default()
let listTableInput = AWSDynamoDBListTablesInput()

dynamoDB.listTables(listTableInput!).continueWith{ (task:AWSTask<AWSDynamoDBListTablesOutput>) -> Any? in
	if let error = task.error as? NSError {
		print("Error occurred: \(error)")
		return nil
	}

	let listTablesOutput = task.result

	for tableName in listTablesOutput!.tableNames! {
		print("\(tableName)")
	}

	return nil
}
  • When migrating legacy Swift code to iOS SDK 2.5.0, continue to use Swift 2.3 syntax for AWS region and service naming conventions. For example: use .USEast1 instead of .usEast1, and use SNS instead of sNS. We made the decision to go against standard Swift 3 naming practices to provide consistency across all AWS region values and service enums.

Swift 3 sample code has been updated and added where appropriate in our AWS Mobile SDK for iOS Samples GitHub repository, in our API reference documentation, and in the AWS Mobile SDK for iOS Developer Guide. Support for a Swift 3 sample app on AWS Mobile Hub is coming soon.

Questions or Comments?

Raise an issue on GitHub or reach out to us via the AWS Mobile Development Forum.

Create an Android Mobile App with Pinpoint using Mobile Hub

by Georgie Mathews | on | in AWS Mobile | | Comments

Amazon Pinpoint is a new AWS service that makes it easy to run targeted campaigns to improve user engagement. Amazon Pinpoint helps you understand your users’ behavior so that you can define who to target, what messages to send, and when to deliver them. Amazon Pinpoint tracks how your users interact with your app so you can monitor the impact of your campaigns.

Amazon Pinpoint provides real-time analytics with dashboards for analyzing user engagement, monetization, user demographics, custom events, and funnels so you can understand how users engage with your app. You can analyze and understand your user data by drilling down based on the segments you’ve defined, segmentation attributes, or time.

With Amazon Pinpoint, you can define target segments from various data sources. You can identify segments from app user data collected by Amazon Pinpoint. You can build custom segments from user data collected by other AWS services, such as Amazon S3 and Amazon Redshift. You can also import user segments from third party sources, such as Salesforce via S3.

Once you define your segments, Amazon Pinpoint lets you send targeted notifications with personalized messages to each user in the segment based on custom attributes, such as game level, favorite team, and news preferences. Amazon Pinpoint can send push notifications immediately, at a time you define, or as a recurring campaign. By scheduling campaigns, you can optimize the push notifications to be delivered at a specific time across multiple time zones. Amazon Pinpoint supports rich notifications, so you can send images as part of your push notifications. Amazon Pinpoint also supports silent or data notifications, which allow you to control app behavior and configuration in the background.

Once your campaign is running, Amazon Pinpoint provides metrics to track the impact of your campaign, including the number of notifications received, number of times the app was opened as a result of the notifications, time of app open, push notification opt-out rate, and revenue. You can also export event data reported by your app and run custom analytics using your existing analytics systems.

You can run A/B tests for different messages, track results, and then send the best message to your target segment.

With Amazon Pinpoint there is no minimum fee, no setup cost, and no fixed monthly cost based on your total user pool. You only pay for the number of users you target or collect events from, the messages you send, and events you collect, so you can start small and scale as your application grows.

Now let’s have a look at how you integrate Amazon Pinpoint with your app.

Requirements

Latest version Android Studio: https://developer.android.com/studio/index.html

Step 1 – Mobile Hub

Create a new Mobile Hub project from the AWS Mobile Hub console. In this example, we are naming the project PinpointMobileHub.

MobileHubCreate

Enable Amazon Pinpoint by clicking User Engagement.

Image2

Enable app and campaign analytics by clicking Enable Engagement.

Choose Android and add your API Key and Sender ID.

EnableUserEngagement

To provide your API Key and Sender ID, refer to the next section for information on how to get these credentials from your Google Developer Project using Firebase.

Getting Sender ID and API Key

Go to https://console.firebase.google.com. Create a new Firebase project called PinpointMobileHub.

Go to your project settings by clicking on the gear icon next to your project name, and then click on Project settings.

Click on the CLOUD MESSAGING tab. Copy the Sender ID (also called Project Number) and the API Key.

Back to Mobile Hub

Provide your sender ID and server key (API Key).

SaveCredentials

Click Save changes. Click Integrate with your app
. You will be redirected to the Integrate feature of Mobile Hub. Click the Android tab to download the Android Mobile Hub sample.

The Android sample contains the Amazon Pinpoint SDK, along with a Demo fragment demonstrating how to record analytics events and how to enrich an endpoint profile with custom attributes so that you can target users based on their preferences.

Mobile Hub Android Sample

Unzip the downloaded file PinpointMobileHub-aws-my-sample-app-android.zip.

IntegrationSteps

Open Android Studio.

Click Open an existing Android Studio project, and navigate to the MySampleApp directory.

Android Studio will open the sample project. Now you should be able to run the sample in your device or on the simulator.

You can verify that your credentials are correct by checking the AWSConfiguration file inside the com.amazonaws.mobile package.
 Verify that your project contains a value for the GOOGLE_CLOUD_MESSAGING_SENDER_ID key.

Note: The Mobile Hub sample project uses the Google Cloud Messaging SDK and not the Firebase SDK. If you are using the Firebase SDK in your application, Amazon Pinpoint will still work with your project, however, there are some extra steps you will need to take to make it work correctly. See the section on Firebase integration.

Run the application on a simulator or device, if you are running the application on the simulator you need to make sure that you have logged in to Google Account on the simulator so that Push Notifications will work on the simulator. To add an account, go to Settings -> Accounts -> Add account -> Google, and log in to your account.

Demo App Analytics

On the demo application, navigate to the User Engagement section and tap on Demo App Analytics.
You will see two buttons on the bottom, the left button records a custom event and the right button records a monetization event.

You can add custom attributes and metrics to an event. The sample code is the following:

 

final AnalyticsClient analyticsClient = AWSMobileClient.defaultMobileClient().getPinpointManager().getAnalyticsClient();

final AnalyticsEvent event = analyticsClient.createEvent(“DemoCustomEvent”) // A music app use case might include attributes such as:
// .withAttribute(“Playlist”, “Amazing Songs 2015”)
// .withAttribute(“Artist”, “Various”)

// .withMetric(“Song playtime”, playTime);

.withAttribute(“DemoAttribute1”, “DemoAttributeValue1”) .withAttribute(“DemoAttribute2”, “DemoAttributeValue2”) .withMetric(“DemoMetric1”, Math.random());

analyticsClient.recordEvent(event); analyticsClient.submitEvents();

 

The sample app records a custom event with event type _monetization.purchase.
You can add also custom attributes and metrics to a monetization event. A monetization event must have a price, a product ID, a quantity, and a transaction id. The sample code is the following:

 

final AnalyticsClient analyticsClient = AWSMobileClient.defaultMobileClient().getPinpointManager().getAnalyticsClient();

// This creates a Google Play monetization event. To create an Amazon monetization
// event instead, use AmazonMonetizationEventBuilder.
final AnalyticsEvent event = GooglePlayMonetizationEventBuilder.create(analyticsClient)

.withFormattedItemPrice(“$1.00”)
.withProductId(“DEMO_PRODUCT_ID”) .withQuantity(1.0) .withTransactionId(“DEMO_TRANSACTION_ID”).build();

analyticsClient.recordEvent(event); analyticsClient.submitEvents();

 

Demo user engagement

We will now run through the user engagement and targeting portion of the demo and get a notification sent to the device.

 

Update an endpoint profile

Amazon Pinpoint is able to segment and target users based on an endpoint profile. The endpoint profile contains information about the device, such as model, make, version, etc., as well as custom attributes or metrics.

To demo the targeting feature of the demo application, navigate to the User Engagement section and tap on Demo User Engagement.

On the User Engagement demo, you will see information about your endpoint profile, such as your current locale, platform, and version. You can also set custom attributes on the endpoint profile. The demo is setting a custom attribute named `season` to signify the favorite seasons of a user.

Go ahead and select your favorite seasons, we will use it later to create a segment that targets devices with those preferences. For this example, we will select all four seasons.

The sample code to update your profile with custom attributes is the following:

.defaultMobileClient().getPinpointManager() .getTargetingClient().addAttribute(“seasons”, Arrays.asList(“winter”,”spring”,”summer”,”fall”)

.defaultMobileClient().getPinpointManager()

AWSMobileClient

.getTargetingClient().updateEndpointProfile();

 

Creating a campaign

Go to the Amazon Pinpoint console: https://console.aws.amazon.com/pinpoint/home/

Select the PinpointMobileHub application we created in Mobile Hub. It will be named pinpointmobilehub_MobileHub since we created the app in Mobile Hub.

Click New Campaign.

Image6

Name your campaign My first campaign, keep the campaign type as a Standard campaign, and click Next step.

Image7

Now let’s create a segment to target users that have selected `Fall` as a favorite season. Name this segment `Fall` so that we can reuse it later.

In the section Filter by custom attributes, select fall and click Next step.

Image8

Give a title and body to the notification, then click Next step.

Schedule the campaign to be Immediate so that you get the notification right away.

Review your campaign and click Launch Campaign.

If you have the sample app in the foreground, an alert will show up. If the sample app is in the background, a banner will be displayed with the notification. You can also swipe down to see the notification center.

If your app is in the background and you tap on the notification, you will be able to see notification opens metrics in the Amazon Pinpoint console as a Directly Opened metric. Click on the Campaign analytics button.

At this point you should also be able to head over to Amazon Pinpoint Analytics and see the monetization and usage data populated in the console, it may take some time for the data to update.

Image9

 

SDK Integration

First add the Amazon Pinpoint SDK to your Gradle Build.

 

dependencies {
// … other dependencies go here …

compile(‘com.amazonaws:aws-android-sdk-core:2.3.5’) // add the Amazon Pinpoint SDK dependency
compile(‘com.amazonaws:aws-android-sdk-pinpoint:2.3.5’) }

 

Initializing the SDK

To initialize the SDK you must instantiate an instance of the PinpointManager class:

 

try {
final CognitoCachingCredentialsProvider cognitoCachingCredentialsProvider =

new CognitoCachingCredentialsProvider( context,
”YOUR_IDENTITY_POOL_ID”, Regions.US_EAST_1,

new ClientConfiguration() final PinpointConfiguration config =

);
new PinpointConfiguration(context, “YOUR_APP_ID”,

Regions.US_EAST_1,

cognitoCachingCredentialsProvider); this.pinpointManager = new PinpointManager(config); //Save instance of pinpointManager

}
catch (final AmazonClientException ex) {

Log.e(LOG_TAG, “Unable to initalize Amazon Mobile Analytics. ” + ex.getMessage(), ex); }

Mobile Hub initializes the SDK inside its AWSMobileClient class. You may use that class to manage initialization of AWS SDKs.

 

Instrumenting Session Data

You must instrument session data manually on Android. You must record session start and stop events in order for Analytics to work. A session must be started before an event is recorded, and they should be stopped once the application goes into the background. Mobile Hub has an example inside its Application class utilizing the AbstractApplicationLifeCycleHelper that provides callbacks to detect when your application goes into the background and comes to the foreground.

The following example is taken from Mobile Hub’s example code:

 

@Override

public void onCreate() {
Log.d(LOG_TAG, “Application.onCreate – Initializing application…”); super.onCreate();
initializeApplication();
Log.d(LOG_TAG, “Application.onCreate – Application initialized OK”);

}
private void initializeApplication() {
AWSMobileClient.initializeMobileClientIfNecessary(getApplicationContext());

// The Helper registers itself to receive application lifecycle events when it is constructed. // A reference is kept here in order to pass through the onTrimMemory() call from
// the Application class to properly track when the application enters the background. applicationLifeCycleHelper = new AbstractApplicationLifeCycleHelper(this) {

@Override
protected void applicationEnteredForeground() {
final PinpointManager pinpointManager = AWSMobileClient.defaultMobileClient()

.getPinpointManager();
pinpointManager.getSessionClient().startSession();
// handle any events that should occur when your app has come to the foreground…

}
@Override

protected void applicationEnteredBackground() {
Log.d(LOG_TAG, “Detected application has entered the background.”);
final PinpointManager pinpointManager = AWSMobileClient.defaultMobileClient()

.getPinpointManager();
pinpointManager.getSessionClient().stopSession(); pinpointManager.getAnalyticsClient().submitEvents();
// handle any events that should occur when your app has gone into the background…

} };

// …Put any application-specific initialization logic here…

}

@Override
public void onTrimMemory(final int level) { Log.d(LOG_TAG, “onTrimMemory ” + level); applicationLifeCycleHelper.handleOnTrimMemory(level); super.onTrimMemory(level);

}
Setting up push notification with GCM

The SDK needs to register the device token received from GCM with the endpoint profile.
Implement the GCMTokenUpdateObserver in a class and override the onGCMTokenUpdate method. The following example is taken from Mobile Hub’s example code:

 

@Override

public void onGCMTokenUpdate(final String gcmToken, final boolean didTokenChange) { if (didTokenChange) {

Log.d(LOG_TAG, “GCM Token changed, registering for Campaign push.”);
// Register the Device Token to receive Campaign Push.
final NotificationClient notificationClient = AWSMobileClient.defaultMobileClient()
.getPinpointManager()

.getNotificationClient(); notificationClient.registerGCMDeviceToken(gcmToken);

} }

 

On your class that extends the GcmListenerService add the following code inside the onMessageReceived method:

 

AWSMobileClient.initializeMobileClientIfNecessary(this.getApplicationContext()); final NotificationClient notificationClient = AWSMobileClient.defaultMobileClient()

.getPinpointManager().getNotificationClient(); NotificationClient.CampaignPushResult pushResult =
notificationClient.handleGCMCampaignPush(from, data, this.getClass());

if (!NotificationClient.CampaignPushResult.NOT_HANDLED.equals(pushResult)) {
if (NotificationClient.CampaignPushResult.APP_IN_FOREGROUND.equals(pushResult)) {

// You can handle the notification any way you like if the app is in the foreground.

}

return;

}

 

Add the following declarations to your AndroidManifest.xml. In this example taken from Mobile Hub, we register the PushListernerService to handle messages.

 

<uses-permission android:name=”android.permission.WAKE_LOCK”/> <uses-permission android:name=”com.google.android.c2dm.permission.RECEIVE” /> <permission android:name=”com.amazon.mysampleapp.permission.C2D_MESSAGE”
android:protectionLevel=”signature” />
<uses-permission android:name=”com.amazon.mysampleapp.permission.C2D_MESSAGE” />

<application

<receiver

android:name=”com.google.android.gms.gcm.GcmReceiver” android:exported=”true” android:permission=”com.google.android.c2dm.permission.SEND” > <intent-filter>

<action android:name=”com.google.android.c2dm.intent.RECEIVE” />

<category android:name=”@string/google_cloud_messaging_package” /> </intent-filter>

</receiver>

<!– BEGIN – PUSH NOTIFICATIONS WITH GOOGLE CLOUD MESSAGING (GCM) –>
<service

android:name=”.PushListenerService” android:exported=”false” > <intent-filter>

<action android:name=”com.google.android.c2dm.intent.RECEIVE” /> </intent-filter>

</service>

 

Setting up push notification with Firebase

The SDK needs to register the device token received from FCM with the endpoint profile. Extend the FirebaseInstanceIdService in a class, and override the onTokenRefresh method.

On your class that extends the FirebaseMessagingService, add the following code inside the onMessageReceived method:

 

@Override

public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken(); AWSMobileClient.defaultMobileClient().getPinpointManager()
.getNotificationClient().registerGCMDeviceToken(refreshedToken); }
NotificationClient.CampaignPushResult pushResult = AWSMobileClient.defaultMobileClient().getPinpointManager().

getNotificationClient().handleFCMCampaignPush( remoteMessage.getFrom(), remoteMessage.getData());

if (!NotificationClient.CampaignPushResult.NOT_HANDLED.equals(pushResult)) {
if (NotificationClient.CampaignPushResult.APP_IN_FOREGROUND.equals(pushResult)) {

// You can handle the notification any way you like if the app is in the foreground.
}

return;

}

 

Add the following declarations to your AndroidManifest.xml. You must register this receiver so that we can launch the app when the user taps on the notification.

 

<receiver

android:name=”com.amazonaws.mobileconnectors.pinpoint.targeting.notification.PinpointNotificationReceiver” android:exported=”false” >
<intent-filter>

<action android:name=”com.amazonaws.intent.fcm.NOTIFICATION_OPEN” /> </intent-filter>

</receiver>

 

Introducing Amazon Lex and Conversational Bots on Mobile Hub

by Akshad Viswanathan | on | in AWS Mobile | | Comments

Last week at AWS re:Invent 2016, we announced the availability of conversational bots, a new feature on AWS Mobile Hub that enables you to create speech or text based conversational bots in your mobile app.

This feature uses Amazon Lex, a new service for building conversational interactions into any application using voice and text. With Amazon Lex, the same conversational engine that powers Amazon Alexa is now available to any developer, enabling you to build sophisticated, natural language, conversational bots (chatbots). Amazon Lex is currently in limited preview. Click here to learn more about Amazon Lex and to request access.

The importance of bots and multimodal user interfaces

With the rapid growth of messaging platforms such as Facebook Messenger and voice controlled devices such as the Amazon Echo, app users are becoming familiar with voice and chat interactions via conversational interfaces. Conversational interfaces, sometimes called ‘chatbots’, understand and communicate using natural language, and provide information or help in completing a task through a series of questions and answers. They provide a more intuitive, efficient way of interacting with applications and devices.

Common use cases for conversational bots include:

· Informational bots to build chatbots for everyday consumer requests, such as accessing the latest news updates, game scores, or weather.

· Application bots to build powerful interfaces to mobile applications. Developers can build chatbots that help customers with many basic tasks, such as accessing their bank accounts, booking tickets, ordering food, or calling a cab.

· Enterprise productivity bots to streamline common work activities and improve organizational efficiencies. For example, employees can check sales data via Salesforce and check marketing performance from HubSpot.

· Internet of Things (IoT) bots to create conversational interfaces for entirely new categories of IoT products, such as cars, devices, wearables, and appliances.

Amazon Lex puts high-quality speech recognition and natural language understanding technologies within reach of all developers, in the form of an easy to use AWS service. You supply just a few example phrases and Amazon Lex builds a complete natural language model through which the bot can interact using voice and text. Integration with AWS services allows you to take advantage of the power of the AWS platform for security, monitoring, user authentication, business logic, storage, and mobile app development. Amazon Lex enables you to easily publish your voice or text chatbots to mobile devices, web apps, and chat services such as Facebook Messenger. Once published, Amazon Lex bot processes voice or text input to conduct a conversation with your end-users. As your user engagement increases, Amazon Lex scales automatically so you don’t need to provision hardware and manage infrastructure to power your bot experience.

Creating your first bot

First, request access for your AWS account to be included in the Amazon Lex Limited Preview program. This process might take up to one business day.

Next, choose the Conversational Bots feature in the Mobile Hub console in a new or existing project.mobile hub tiles

Select one of the three sample bots and click the Create Bot button.

Mobile Hub will create your bot on Amazon Lex with sample intents and utterances. An intent performs an action in response to a natural language user input, while an utterance is a set of spoken or typed phrases that invoke your intent. You can learn more about how Amazon Lex chatbots work from the Amazon Lex Developer guide.

Once you have created a bot, click the Integrate tab in Mobile Hub.

integrate

 

Choose Getting Started on the left navigation menu and then select the platform (iOS Swift, iOS Objective-C, Android) tab that corresponds to your app. Then, choose Download the sample app. We will use Android in this example.

download-sample

The project you download contains working sample code that is generated based on the selections you made. The code integrates with the backend services Mobile Hub provisioned for you. It implements client code to interact with your bot using voice or chat. Unzip the folder and open the project in Android Studio by choosing the project level build.gradle file. Run the sample app in your emulator and try signing up a user.

test-bots

 

 

 

 

Integrating a bot with your app

The easiest way to integrate a bot with your app is to follow the integration instructions in the Integrate tab. You can integrate existing bots you have created on Amazon Lex using the Import a Bot option in the conversational bots feature.

Ensure you have completed the steps in the Getting Started section. This includes allowing network access, including the AWS SDKs, and copying Hub helper and custom code. Next, choose the Conversational Bots section and follow the step-by-step guidance to copy Android or iOS client code for the voice or text interfaces.

So get started today with both these features on AWS Mobile Hub. If you have questions or feedback, please use the comment section or visit our forums.

Introducing Mobile Hub user authentication using SAML Federation or Email and Password sign-in

by Trent Peterson and Akshad Viswanathan | on | in AWS Mobile | | Comments

We are excited to announce two new options for user authentication in mobile apps – Email and Password and SAML Federation. Both features are options in the User Sign-in feature of AWS Mobile Hub. Along with the existing Facebook and Google sign-in options, you can mix and match these new sign-in provider options to setup the authentication flow that your app needs in minutes.

Under the hood, Mobile Hub provisions and configures all the required AWS services on your behalf. That includes Amazon Cognito for authentication, AWS Identity and Access Management (IAM) for access authorization, and service like DynamoDB tables or S3 buckets. Mobile Hub also uses the options you select to dynamically generate working sign-up, sign-in, and password recovery flow code in a Quickstart app you can download and use directly or customize for your app.

In this post, we cover details on each of these new options and how you can apply them in business-to-consumer (B2C) or business-to-employee (B2E) mobile apps.

Email and Password Authentication

The Email and Password option provisions a user directory called a user pool. The user pool stores user identities and profile attributes and is the source of authentication when your users sign-in to your app. Mobile Hub uses Amazon Cognito Your User Pools to manage and validate user identities. You can combine the Email and Password option in addition to the Facebook and Google sign-in options and allow your users to choose the account they prefer to sign-in to your app.

Mobile Hub allows you to configure password policies for your users. You can also choose to enable multi-factor authentication via SMS.

Enabling the user sign-in option

In the Mobile Hub console, choose the User sign-in feature in a new or an existing project.

Using sign-in

Choose the Email and Password option. The Mobile Hub console provides you with choices and suggested defaults for configuring the user sign-in experience your user pool. You can configure:

–       What identifier the user provides to sign-in/sign-up to your app (email, usernames, and passwords),

–       If multi-factor authentication is enabled and whether it is optional or requires

–       Password policies (minimum password lengths and character requirements)

Enable SMS-based Multi-factor authentication (MFA) to make logins more secure. With SMS-based MFA enabled, your users will be prompted for their password (the first factor) and for a security code that can only be received on their mobile phone via SMS (the second factor). The user is required to provide a phone number during sign-up.

Enabling MFA

Choose Create user pool. Mobile Hub will provision your user pool on Amazon Cognito with the configuration you selected.

Next, choose between Optional and Required sign-in. Required means that the user sign-in flow of the Quickstart app Mobile Hub will generate requires sign-in before any usage of the app can occur. Choose Save if you elected to require sign-in.

Running the sample app

Once you have setup your user pool, you can use the Quickstart app to add sign-up, sign-in, and password recovery flows to your app. Choose Integrate the left hand menu of your project.

 

Integerate tab

Choose Getting Started on the left hand menu and and then select the platform (iOS Swift, iOS Objective-C, Android) tab that corresponds to your app. Then, choose Download the sample app.

 

Download sample app

The project you download contains working sample code generated based on the selections you made that integrates with the backend services Mobile Hub provisioned for you. It implements client sign-up, sign-in, and password recovery flows that can be used directly in your project or as examples for your customization.

Unzip the folder and open the project in Android Studio by choosing the project level build.gradle file. Run the sample app in your emulator and try signing up a user. Then, sign in to the app with the credentials you just created.

Sample app in emulator

Adding sign-in to your own app

The easiest way to add sign-in to your own app is by following the integration instructions in the Integrate tab. Ensure you have completed the steps in the Getting Started section. This includes allowing network access, including the AWS SDKs, and copying Hub helper and custom code. Next, choose the User Sign-in section and follow the step-by-step guidance to copy Android or iOS client code for sign-up and sign-in.

SAML Federation

You can use the SAML Federation option to authenticate users through your own SAML identity provider (IdP) and provide secure access to AWS resources, such as Amazon S3 and Amazon DynamoDB, through Amazon Cognito. Your IdP must support SAML 2.0 (Security Assertion Markup Language 2.0) to federate with AWS.

First, you need to exchange trust between your SAML provider and AWS. To do this, select the SAML Federation option in the User Sign-in feature.

SAML

Next, upload the SAML federation metadata document you received from your IdP and create a new provider.

This file typically includes the issuer’s name, expiration information, and a certificate that can be used to validate the SAML assertion response received from the IdP. For Microsoft Active Directory Federation Services (ADFS), you can download the document from:

https://<yourservername>/FederationMetadata/2007-06/FederationMetadata.xml

For more information related to different SAML IdPs, see Integrating Third-Party SAML Solution Providers with AWS.

Next, configure your IdP with AWS certificates and then add SAML authentication and access control to your app. The AWS SAML federation metadata can be found at:

https://signin.aws.amazon.com/static/saml-metadata.xml

After that you can add SAML to your own app. We provide you with step-by-step flow for completing both of these tasks in the Integrate tab.

So get started today with both these features on AWS Mobile Hub. If you have questions or feedback, please use the comment section below or visit our forums.

Streaming videos to millions of mobile app users via Amazon CloudFront CDN

by Dennis Hills | on | in AWS Mobile, CloudFront, Elastic Transcoder, HLS, Lambda, S3, Streaming Video | | Comments

Update: March 17, 2017

This post has been updated to address a few operational issues and overall feedback from developers and internal teams. We hope you enjoy and please keep the comments and contributions flowing!

Changes:

  • If the Lambda function is/was not getting triggered after a video was uploaded to S3, see new note about your suffix in step 3C. Oh, and the suffix IS case-sensitive. So a suffix of MP4 will not match with a video uploaded as rafting.mp4.
  • The event trigger is now configured through the Lambda Console with new screenshots. Also, when creating an event trigger, a Lambda Function Policy is automatically created allowing S3 to invoke the Lambda function.
  • Best practices: We added a warning in section 2A stating that you should always create a separate S3 bucket, one for video input and another one for storing the encoded HLS video playlists and segments.

Happy encoding! -Dennis


About

Welcome to the second installment of our blog series (the first post is here) showing how to build some of the most popular end-to-end experiences used by mobile apps.

This post is about HTTP Live Streaming (HLS) video content via Amazon CloudFront to your mobile application. You’ll utilize AWS Mobile Hub to enable the App Content – Global CDN feature that provisions an Amazon S3 bucket to store our streaming content and creates an Amazon CloudFront Web Distribution that will cache your video files using your Amazon S3 bucket as the source (origin) in edge locations around the world. This provides fast, low latency access to your content from mobile devices around the world. In addition, you’ll enable the Cloud Logic feature and use AWS Lambda to automatically generate transcoding jobs for videos uploaded to your S3 bucket.

You’ll walk away with a fully functioning mobile application streaming your own encoded HTTP Live Streaming (HLS) video on demand (VOD) directly from your Amazon CloudFront Web Distribution. This a complete end-to-end solution demonstrating a very common mobile cloud video distribution architecture.
There are five steps in this tutorial.

Step 1. Configure the backend AWS resources via AWS Mobile Hub. This consists of creating a project, enabling features App Content Delivery – Global CDN and Cloud Logic for transcoding videos via Amazon Elastic Transcoder.

Step 2. Staging video and provisioning Amazon S3, AWS Lambda, and Amazon Elastic Transcoder pipeline to be used for transcoding a basic HD video into HLS.

Step 3. Upload video to S3 and encoding HLS content

Step 4. Modify the sample app project code generated by Mobile Hub to explore and stream HLS video content from Amazon CloudFront using the transcoded media files stored in S3.

Step 5. Streaming HLS video content from your own app by following the AWS Mobile Hub integration guide customized for your project.

First, we’ll explain briefly what HLS is, how it works, and how to use Amazon Elastic Transcoder to transcode media into the HLS format. We’ll then briefly explain AWS features (Amazon S3, AWS Lambda, and Amazon CloudFront) that you’ll enable within a Mobile Hub project.

What is HLS?
HTTP Live Streaming (HLS) is a protocol that segments media files for optimization during streaming. HLS enables media players to play segments with the highest quality resolution that is supported by their network connection during playback.
In Step 3 you’ll transcode an HD action movie (filmed on a GoPro) into HLS segments, copy those media files to S3, and stream this content from our modified sample app in Step 4.

What is AWS Lambda?
The Cloud Logic feature is powered by AWS Lambda functions. These functions allow you to simply write code without worrying about managing frameworks and scaling of backend infrastructure. You can write your functions in JavaScript, Java, or Python. You’ll be using Lambda to create encoding jobs via Amazon Elastic Transcoder whenever a video is uploaded to your S3 bucket. Learn more about AWS Lambda

Transcoding HLS using Amazon Elastic Transcoder
Transcoding is the process of converting a media file (audio or video) from one format, size, or quality to another. Elastic Transcoder takes input from an S3 bucket, transcodes it, and writes the resulting file to another bucket or folder. You start with one or more input files and create transcoding jobs in a transcoding pipeline for each file. Each job must reference a particular transcoding preset, and in our case will result in the generation of HLS segments and playlists. Our Lambda starter code will be the job creator and is configured with all the HLS transcoding presets available. Learn more about Elastic Transcoder.

What is Amazon S3?
Amazon Simple Storage Service (Amazon S3) provides secure, durable, highly scalable object storage in the cloud. Using the AWS Mobile SDK, you can directly access Amazon S3 from your mobile app. The AWS Mobile SDK allows you to consume the Amazon S3 service in your mobile application via the S3 Transfer Utility. The fully functional iOS sample app generated by Mobile Hub includes the AWS Mobile SDK for iOS and all the helper code for running the demo app. For this tutorial, you’ll create an S3 bucket and use it to store the video content. The S3 bucket acts as the origin (source of distributed content) for your CloudFront Web Distribution. Learn more about Amazon S3 cloud storage and pricing.

What is Amazon CloudFront?
Amazon CloudFront is a global content delivery network (CDN) service that accelerates delivery of your websites, APIs, video content, and other web assets. It integrates with other AWS services to give developers and businesses an easy way to accelerate content delivery to end users with no minimum usage commitments. For this tutorial, you’ll use CloudFront to distribute HLS streaming content to a mobile device. Learn more about Amazon CloudFront and pricing.

Let’s Begin

Step 1 – Configure your backend content delivery

You’ll use Mobile Hub to create a project. Next, you’ll enable the App Content Delivery feature to store our video content on Amazon S3 and Cloud Logic to launch encoding jobs to encode HLS content. We’ll walk you through the steps and follow up with a recap (explain the magic) of what just happened.
1. Launch AWS Mobile Hub console

2. Select Create new mobile project

step1-2

3. Provide a project name, (e.g. StreamingBlog) and then select Create project.

CreateProject

Note: If you have never used Mobile Hub before, you’ll be prompted to select Get Started and Yes, grant permissions before you can create a new project.
4. Select App Content Delivery.

MH-Select-AppContentDelivery

5. Select Global CDN and then choose Save changes.

MH-Select-GlobalCDN-Save

6. Select Configure more features button so we can enable one additional feature.
7. Select Cloud Logic.

cloud-logic-new

8. Select Create new API.

create-new-api

9. Provide the following properties to create your Cloud Logic API.

  1. API name: encoder
  2. Description: Encoding Job Trigger
  3. Change path to: /encoder
  4. Change Lambda function name to: encoderHandler
  5. Select Create API

create-api-new

Wait for the API to finish deploying…

api-deployed

10. Select Integrate from the left panel.

step1-6

From the integration tab, make sure iOS Swift is selected and that you are in the Getting Started section.
11. Select the iOS Swift tab and select Download a sample app to download your iOS Swift project source code. We’ll run this project in Xcode in a later step. Note: You may have to wait a few minutes for Cloud Logic API finalize deployment before you can download the sample app project code.

download-sample-app

Done. You now have all of your AWS resources configured and the custom-built iOS Swift source code project is downloaded and ready.

What did we just do?
First, you created a new project in AWS Mobile Hub. Note that, for each Mobile Hub project created, an Amazon Cognito identity pool is created on your behalf, regardless of which features are enabled. For this tutorial, we are only utilizing Amazon Cognito, giving permission to list the content of the S3 bucket that you are using as the source for streaming media.

After the project was created with the default Amazon Cognito identity pool, you then enabled the App Content Delivery and Cloud Logic features in your Mobile Hub project.

The App Content Delivery feature first creates an Amazon S3 bucket to store media content and creates a policy within the AWS Identity and Access Management (IAM) role that grants your users access to list all content in your Amazon S3 bucket when they launch the app. Within the S3 bucket, Mobile Hub has uploaded five sample images (e.g., example-image-1.png).

The Cloud Logic feature created an “encoder” API with a Node.js Lambda function along with its own IAM role that allows the Lambda function to call other AWS services such as Amazon Elastic Transcoder. This Lambda function will become your HLS Amazon Elastic Transcoding encoding job creator when new videos are uploaded to your origin S3 bucket via an S3 Event.

Finally, you downloaded the generated project source code to run the Mobile Hub sample app demonstrating the features you just configured.

How does the sample app work?
You’ll open the iOS Swift project source project in Xcode to build and run the sample app. Upon first launch of the app, that user is given a unique unauthenticated Amazon Cognito Identity. The user then selects the App Content Delivery feature that lists the sample images from your S3 bucket you just configured. From this demo, the user can choose to Open Remote or Download the sample image. For Open Remote, the image is actually cached from S3, downloaded directly from CloudFront, and viewed in the provided WebViewController. For Download, the app downloads the cached content from CloudFront and caches it locally on the device. You can then open the image offline because it’s now stored on the device.

After running through a few more steps below, you’ll re-launch the app and instead of selecting the sample image, select the HLS master playlist (.m3u8 file) from the list. The app will begin streaming the cached HLS movie natively from your CloudFront Web Distribution using the iOS MoviePlayerController on the device.

Step 2 – Stage Video Content and Encoding Service

In this step, you’ll be doing some backend provisioning to set the stage for storing video content on S3, triggering encoding jobs via Lambda, and creating an Amazon Elastic Transcoder pipeline to transcode our HD video into HTTP Live Streaming (HLS) segments.

This step is broken into five important tasks and we’ll walk you through each one now.

A. Create an Elastic Transcoder Pipeline

Launch the Elastic Transcoder Management Console in the same region as your Mobile Hub project and select Create New Pipeline.

create-new-pipeline

For the bucket locations, choose the App Content Delivery S3 bucket that was created by Mobile Hub. The field should auto-populate a list of your S3 buckets, taking any guess work away. Leave the default setting for IAM Role and set Storage Class to Standard. Your new pipeline configuration should look something like below. The Notifications and Encryption section can be ignored for this tutorial.

WARNING: Since we are automating this process using S3 events triggering Lambda to create transcoder jobs, you should always specify a different OUTPUT S3 bucket to hold the finalized Transcoded Files! This is why the suffix reference above was so important to avoid run-away recursion in Lambda where newly encoded videos are uploaded to the same S3 bucket. For this tutorial, we are going against this recommendation to simplify the workflow for demonstration purposes. :)

create-pipeline
Once you have provided the details, select the Create Pipeline button on the lower right. You just created a new Elastic Transcoder Pipeline.
Save for later: Copy the Pipeline ID from the Pipelines Summary as we’ll reference this in your Lambda function in the next task.

pipeline-id

B. Modify the “encoder” Lambda function.

You enabled Cloud Logic earlier, which created a Lambda function within your project. You are now going to overwrite that default function code with the provided Lambda code below.

First, go back to your Mobile Hub project and select Resources from the left navigation and then select the “encoderHandler” link from the AWS Lambda Functions card to launch the function in the AWS Lambda console.

lambda-function-new

The code editor that appears for the encoder function should look something like this.

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

'use strict';
console.log("Loading function");

exports.handler = function(event, context, callback) {
    var responseCode = 200;
    var requestBody, pathParams, queryStringParams, headerParams, stage,
    stageVariables, cognitoIdentityId, httpMethod, sourceIp, userAgent,
    requestId, resourcePath;
    console.log("request: " + JSON.stringify(event));

    // Request Body
    requestBody = event.body;

    if (requestBody !== undefined && requestBody !== null) {

        // Set 'test-status' field in the request to test sending a specific response status code (e.g., 503)
        responseCode = JSON.parse(requestBody)['test-status'];
    }
...

You are now going to overwrite the “encoder” API code from above with the starter code below. Just copy this code below and paste it into the Lambda function code editor.

//Author: Dennis Hills
//Date: March 15, 2017
//Purpose: HLS Streaming mobile blog
//Requirements: An Elastic Transcoder Pipeline

var aws = require('aws-sdk');
var elastictranscoder = new aws.ElasticTranscoder();

// return filename without extension
function baseName(path) {
   return path.split('/').reverse()[0].split('.')[0];
}

exports.handler = function(event, context) {
    console.log('Received event:', JSON.stringify(event, null, 2));
    var key = event.Records[0].s3.object.key;
    var outputPrefix = baseName(key) + '-' + Date.now().toString();

    var params = {
      Input: { 
        Key: key
      },
      PipelineId: '1476775662902-2dp0az', /*Your Elastic Transcoder Pipeline Id*/
      OutputKeyPrefix: 'HLS/' + outputPrefix,
      Outputs: [
        {
          Key: '/output/2M',
          PresetId: '1351620000001-200015', // HLS v3 and v4 (Apple HTTP Live Streaming), 2 megabits/second, Video-only
          SegmentDuration: '10',
        },
        {
          Key: '/output/15M',
          PresetId: '1351620000001-200025', // HLS v3 and v4 (Apple HTTP Live Streaming), 1.5 megabits/second, Video-only
          SegmentDuration: '10',
        },
        {
          Key: '/output/1M',
          PresetId: '1351620000001-200035', // HLS v3 and v4 (Apple HTTP Live Streaming), 1 megabit/second, Video-only
          SegmentDuration: '10',
        },
        {
          Key: '/output/600k',
          PresetId: '1351620000001-200045', // HLS v3 and v4 (Apple HTTP Live Streaming), 600 kilobits/second, Video-only
          SegmentDuration: '10',
        },
        {
          Key: '/output/400k',
          PresetId: '1351620000001-200055', // HLS v3 and v4 (Apple HTTP Live Streaming), 400 kilobits/second, Video-only
          SegmentDuration: '10',
        },
        {
          Key: '/output/aud',
          PresetId: '1351620000001-200060', // AUDIO ONLY: HLS v3 and v4 Audio, 160 k
          SegmentDuration: '10',
        }
      ],
      Playlists: [
        {
            Format: 'HLSv4',
            Name:  '/' + baseName(key) + '-master-playlist',
            OutputKeys: [ '/output/2M', '/output/15M', '/output/1M','/output/600k', '/output/400k', '/output/aud']
        }
      ]
    };

    elastictranscoder.createJob(params, function(err, data) {
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log(data);           // successful response
    });
};

Critical Step: Before saving the Lambda code, change the PipelineId to your Elastic Transcoder Pipeline Id that you copied in the previous task. That is the only code change needed for this Lambda function. Select Save.

pipeline-id-code

C. Create a Lambda trigger to respond to S3 events

From the Lambda Console with your function selected, select the Triggers tab.

addTrigger1

Select S3 as your trigger type and provide the following details as shown.Bucket: Select your content Content Delivery S3 bucket

  1. Event Type: Object Created (All)
  2. Prefix: <leave blank>
  3. *Suffix: mp4
  4. Submit

Trigger-Main

*Please Note*: The Suffix is really important here. The suffix is stating that this Lambda function should only be invoked by S3 when an object is uploaded to S3 with an mp4 extension. Otherwise, you would trigger this encoder for all the file types uploaded to this bucket. Put in a suffix that matches your incoming video type (e.g. avi, mov, mpg, mp4). Also, only put ONE suffix into a single trigger. If you want to whitelist more than one suffix, add another trigger with a different suffix.

That’s it for creating an S3 event to trigger the Lambda function.
How does this S3 event trigger work? Whenever you upload a video (with a suffix matching your filter) into the S3 bucket, S3 will invoke (S3 has permission to invoke this function based on the auto-generated function policy) your encoder Lambda function and passes the video filename (and other attributes) to this function. Lambda then starts the transcoding job(s) to convert the uploaded video into HLS segments for streaming. Automation, baby!

D. Allow Lambda to create Elastic Transcoder Jobs.

By default, your encoder function was created with a limited IAM execution role as it was intended to only return your request back to you for demonstration purposes. Now, we need to allow Lambda to call the Elastic Transcoder Service.

Go back to your Mobile Hub project and select Resources from the left navigation pane and then select the Lambda Execution Role to launch the role in the IAM console.

lambda-execution-role-resource

In the IAM console for the Lambda Execution role, select Edit Policy under the Inline Policy section as shown.

Edit-IAM-Execute-Policy

Within this policy, we are adding permission to call the Amazon Elastic Transcoder CreateJob API. Copy the statement below and paste it into the policy as shown. The highlighted yellow area is the newly appended action after pasting into the policy document editor for the lambdaexecution policy.

{ "Effect": "Allow",
"Action": [
"ElasticTranscoder:CreateJob"
],
"Resource": "*"
}

Updated-Execute-Policy

Select Apply Policy. Now Lambda has access to create transcoding jobs within Elastic Transcoder when triggered by S3 after a new video is uploaded to your Content Delivery S3 bucket. Sweet!

E. Grant CloudFront read permissions by adding a bucket policy just for CloudFront.

For this task, you need to edit the origin configuration for your CloudFront Web Distribution so that it has permission to read from your content delivery S3 bucket for caching the newly transcoded files. By default, Mobile Hub creates the Web Distribution so that all objects in the S3 bucket (origin) need to be Public for the distribution to cache those files. Making this change keeps the restricted access to the S3 bucket but allows CloudFront to read objects without you having to manually update the object permissions in the bucket after each PUT or after transcoding.

Start by going to your Mobile Hub project resources and select the CloudFront Web Distribution.

cdn-config-1

Within the CloudFront console, select the Origins tab, then select the S3 bucket origin, and select Edit.

cdn-config-2
Configure the Origin Settings as shown in the following image and select Yes, Edit button on lower right (not shown).

cdn-3

Now CloudFront can access all the contents of your S3 bucket and cache upon request, while keeping your S3 content protected. That was the final task for Step 2.

What did we just do in Step 2?
You just completed Step 2 with five important tasks. Congratulations. It was a big step. In the first task, (A), you created and configured an Amazon Elastic Transcoder pipeline. This pipeline sets the stage for encoding jobs that will convert your videos into HLS segments. In the second task, (B), you modified the “encoder” Lambda function by pasting in the starter code and provided your Elastic Transcoder pipeline ID. In the third task, (C), you enabled an S3 event in your Content Delivery S3 bucket to trigger a Lambda function when you PUT new videos in the bucket. In the fourth task, (D), you modified the Lambda IAM execution policy, allowing it to call the Elastic Transcoder APIs. In the final task, (E), you modified the Origin Settings of the CloudFront Web Distribution, restricting access to your S3 bucket and allowing this distribution to read all contents within the S3 bucket to cache when requested.

Now that we have everything configured on the backend for storing, distributing, and encoding media content, you’ll focus on the client-side project code, upload a video, and start streaming!

Step 3 – Upload video to S3 and trigger HLS encoding

In this step, you’ll download a sample video and upload it to your Content Delivery S3 bucket to begin encoding it to HLS for streaming.

1. Download sample 1-minute HD video (approx. 388MB) here. You can skip this step if you want to upload your own video in the next step!
2. Upload the provided video (or your own .mov or .mp4) to your Content Delivery S3 bucket, using the S3 console here.
3. Select Upload.
4. Select Add Files.
5. Select the video you want to upload.
6. Select Start Upload.
Note: It may take several minutes to upload the video via the S3 console. If you have the AWS CLI or another S3 client, feel free to utilize any of those tools to speed up the process of uploading content to your S3 bucket.

What did we just do?
In this step you just uploaded a video to your Content Delivery S3 bucket. When the file upload completed, your S3 PUT event triggered the Lambda function to begin transcoding your video into HLS segments. For a 1-minute video, the transcoding of all the segments and playlists should be done in less than a minute.

What does the transcoding look like? Once transcoding is complete, you’ll see an HLS/ folder in your bucket and within that folder you’ll see a folder with the video filename, appended with a date string. Within that sub folder is the HLS 4 playlist (.m3u8) and an output/ folder containing all the encoded HLS segments.

encoded-folder-s3

Here’s what the output folder looks like, containing all the various bitrates, iframes, and playlists.

hls-output-folder

From the mobile app you are about to configure, you’ll select the master playlist (rafting-playlist.m3u8) from the S3 bucket list demo and the transcoded video will automatically begin streaming the cached video from CloudFront.

Step 4 – Modify sample app and stream HLS content

In this final step, you just need to make one small modification to the iOS Swift project source code so that it sees the .m3u8 file type as a video file. Remember downloading the source project in Step 1?
Start by opening the project code in Xcode on your Mac.
1. Unzip the iOS Swift project code you downloaded previously.

streamin-zip-folder

2. Open the sample app project in Xcode by double-clicking on the Xcode project, MySampleApp.xcodeproj, which is in the project folder.

step2-2

3. Expand the project folders and open the ContentDeliveryViewController.swift class. Add the highlighted line as shown to your isAudioVideo() function. This allows the app to identify your HLS 4 playlist as video content.

add-HLS

4. Select build/run within Xcode to build and run the sample app.
5. At the main screen of the sample app, select App Content Delivery and then Demo Content Delivery.

app-content-main    app-content-1

 

7. Select the HLS/ folder and the newly encoded video folder.
8. Tap on the HLS playlist (.m3u8 file) and choose Open Remote.

playlist

The app will automatically start streaming the video choosing the correct bitrate for your connection speed. The app is using the default iOS MPMoviePLayerViewController and it does all the heavy lifting to determine the best way to stream the video content.

video-playing

The magic is that you should experience the same playback quality and smoothness regardless of the network the device is connected to. Switching the app from Wi-Fi to cellular, the built-in player will auto-adjust and begin or continue playing the same video using one of the different bitrate variants you provided when transcoding the original source mp4 video into HLS.

Now, to really see the power of HLS encoded video, play around with the app connection (switching from Wi-Fi to cellular) and see how it performs.

More cool stuff to play with: To highlight the power of HLS streaming content from CloudFront, just select the original .mp4 video source and the app will automatically start playing the movie. If you have a modern device and great bandwidth, you may not notice much. However, try the same source video on another older device or over a slower connection. Doing this, you’ll see the device will have a hard time playing the video without lag, artifacts, or other unbearable viewing experiences. Repeat the same process by selecting the HLS master playlist and you should notice a significant difference in playability.

Planning to integrate this feature into your own app? No problem! In the next step, we’ll walk you through the Mobile Hub integration guide, helping you integrate all the code from the sample app into your own app.

Step 5 – Streaming HLS content to your own app

You just configured backend content delivery and ran our generated sample app to demonstrate the end-to-end functionality of this common mobile feature. To get the same functionality in your own app, use the Mobile Hub integration instructions specific to each mobile project you create.

Let’s get started.
Go back to your Mobile Hub project in the console and select Integrate. The integration instructions from Mobile Hub walk you through Getting Started. The instructions then describe each feature you enabled in your Mobile Hub project and how to integrate each of them into your own app.
Here’s a quick overview of Getting Started and additional instructions for integrating this project into your own application.
The Mobile Hub Getting Started integration instructions include:

  • Download the Mobile SDK for iOS and custom source code provided
    The download provides the latest SDK, Mobile Hub helper code, and example source code to get you started.
  • After downloading the SDK and helper code, drag and drop the Sdk folder contained in the download into your own project within Xcode. This assumes you already have an iOS Swift project of your own; if not, create a new one and follow along.
  • Add the AWS SDKs as Embed Frameworks.
  • Add Run Script phase to your project as directed.
  • Copy the AmazonAws folder from the helper code to your project and add a group for it. This source code contains a customized helper framework that simplifies the use of all the SDKs that are required to support your project.
    It also contains the AWSMobileClient.swift file, which bootstraps the app and creates an identity manager to establish the user identity with Amazon Cognito.
  • Copy the AWS dictionary from the integration Info.plist into your own project Info.plist. The AWS dictionary provides the CognitoIdentity poolId and region for your project.
  • Add AWS iOS SDK dependencies, libsqlite3.tbd and libz.tbd, under Linked Frameworks and Libraries as directed.
  • Set up your Application Delegate by returning the AWSMobileClient singleton as shown in the guide.

You are now done with the Getting Started section.
After you complete Getting Started, you can select App Content Delivery in the left panel of the integration instructions. Here, you just need to do the following:

  • Copy the ContentManager key from the AWS dictionary in the integration Info.plist into your own project’s Info.plist. The AWS dictionary already provides all the CognitoIdentity pool IDs for your project as well as your Content Delivery S3 bucket and region.
  • View or copy the example upload/download source code provided.

That’s it! You should now be able to run your own application and connect it to your AWS resources like we demonstrated using the sample app generated by AWS Mobile Hub.

Conclusion

You just configured a backend app content delivery feature via AWS Mobile Hub; generated a fully functional sample iOS app that demonstrates opening and streaming videos directly from your Amazon CloudFront CDN; and then walked through integrating the client code into your own app by connecting to the same backend resources demonstrated in the sample app.

Thanks and happy coding!

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 &amp;&amp; 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 &amp;&amp; event.request.session[1].challengeName == 'PASSWORD_VERIFIER' &amp;&amp; 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 &amp;&amp; event.request.session[2].challengeName == 'CUSTOM_CHALLENGE' &amp;&amp; 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.

How to Store Your App Photos in the Cloud Using Amazon S3 [tutorial and code samples]

by Dennis Hills | on | in AWS Mobile, CloudFront, Elastic Transcoder, HLS, Lambda, S3, Streaming Video | | Comments

About

Welcome to the first installment of our blog series showing how to build some of the most popular end-to-end experiences used by mobile apps. In each installment, you’ll see how you can build these experiences – including the client (iOS and Android) and the backend (AWS services) – in just a few minutes. We’ll typically use AWS Mobile Hub to accomplish this; Mobile Hub simplifies many of the steps you would normally have to go through, including authenticating users, securely configuring backend services, running backend code, and generating reference iOS and Android apps that use these features. We’ll then dive deeper, showing you how to integrate the experiences into your own applications and explaining what is happening within Mobile Hub.

Through the series, we’ll touch on a number of AWS services, including Amazon Cognito, Amazon S3, Amazon DynamoDB, and AWS Lambda. We welcome your suggestions in the comments for additional experiences or AWS services we should highlight!

Let’s get started with our first installment. This first post is about uploading photos to and downloading photos from the cloud from a mobile application. You’ll walk away with a fully functioning mobile application connecting to your AWS backend resources.

There are three steps in this tutorial.

Step 1. Configure the backend AWS resources via AWS Mobile Hub. This consists of creating a project, enabling a single feature called User Data Storage, and building/downloading the iOS Swift sample app source code project.

Step 2. Explore uploading to and downloading photos from Amazon S3 using the sample app generated by Mobile Hub.

Step 3. Store and Retrieve Photos from your own app by following the AWS Mobile Hub integration guide customized for your project.

First, we’ll explain briefly what Mobile Hub is and the AWS features (Amazon S3 and Amazon Cognito Identity) that we’ll enable within a Mobile Hub project.

What is AWS Mobile Hub
AWS Mobile Hub simplifies the process of building, testing, and monitoring mobile applications that make use of one or more AWS services. It can help you skip the front- and back-end heavy lifting of manually creating cloud service configurations and integrating them into your client.  The mobile app features supported includes user authentication, data storage, backend logic, push notifications, content delivery, and analytics—all from a single, integrated console.

There is no charge for Mobile Hub; you only pay for the AWS services used. For example, after you complete this tutorial, you are only charged for the objects stored in your S3 bucket. Learn more about AWS Mobile Hub features.

What is Amazon Cognito Federated Identity
Amazon Cognito Federated Identities enable you to create unique identities for your users and authenticate them with identity providers. With an identity, you can obtain temporary, limited-privilege AWS credentials to synchronize data with Amazon Cognito Sync, or directly access other AWS services. Amazon Cognito Identity supports public identity providers—Amazon, Facebook, Google, and SAML identity providers—as well as unauthenticated identities, which is what we’ll be utilizing in this tutorial. Learn more about Amazon Cognito Federated Identities.

What is Amazon S3
Amazon Simple Storage Service (Amazon S3) provides secure, durable, highly scalable object storage in the cloud. Using the AWS Mobile SDK, you can directly access Amazon S3 from your mobile app. The AWS Mobile SDK allows you to consume the Amazon S3 service in your mobile application via the S3 Transfer Utility. The fully functional iOS sample app generated by Mobile Hub includes the AWS Mobile SDK for iOS, S3 Transfer Utility, and all the helper code for running the demo app used for this tutorial. Learn more about Amazon S3 cloud storage and pricing.

Let’s Begin

Step 1 – Configure the backend

We’ll use Mobile Hub to create a project and then enable the User Data Storage feature to store and retrieve photos from Amazon S3. We walk you through the steps and follow up with a recap (explain the magic) of what just happened.

1)  Launch AWS Mobile Hub console

2)  Select Create new mobile project.

3)  Provide a project name, S3Blog, and then select Create project.


Note: If you have never used Mobile Hub before, you’ll be prompted to select Get Started and Yes, grant permissions before you can create a new project.

4)  Select User Data Storage.


5)  Select Store user data and then choose Save changes.


6)  Select Integrate from the left panel


7)  From the integration tab, make sure iOS Swift is selected and that you are in the Getting Started section.
8)  Select Download a sample app to download your iOS Swift project source code (zipped project folder). We’ll run this project in Xcode in just a minute.

Done. You now have all your AWS resources configured and the custom-built iOS Swift source code project is downloaded and ready.

What did we just do?

First, we created a new project in AWS Mobile Hub. Note that, for each Mobile Hub project created, an Amazon Cognito identity pool is created on your behalf, regardless of what features are enabled. Amazon Cognito Identity is being used in our app to obtain temporary, unauthenticated, limited-privilege credentials to directly access Amazon S3 from a mobile app.

In a future blogpost, we’ll discuss the Mobile Hub User Sign-in feature where Amazon Cognito provides authenticated identities through Amazon Cognito User Pools and public identity providers—Amazon, Facebook, Google, and SAML. for this tutorial, just know that we’ll be using Amazon Cognito unauthenticated identities to demonstrate this topic.

After the project was created with the default Amazon Cognito identity pool, you then enabled the User Data Storage feature in your Mobile Hub project. This feature first creates an Amazon S3 bucket to store user photos and creates a policy within the AWS Identity and Access Management (IAM) role that grants your user’s access to Amazon S3 when they launch the app. Within the S3 bucket, a /Public folder was created with access permissions set to allow all users of your app to view and upload files stored there. There’s also a /Private folder created, which we’ll discuss in the next blog post. This folder is used to store private data for each user when authenticated through the User Sign-in feature of Mobile Hub.

Here’s how the sample app works:

The user launches the app and immediately that user is given a unique unauthenticated Amazon Cognito Identity. The user then selects the User Data Storage demo feature to upload a photo from his or her photo library to the /Public folder within the S3 bucket. The unique unauthenticated Amazon Cognito Identity given to that user provides limited-privilege credentials to directly access the /Public folder of your S3 bucket.

Now that we have created file storage that is designed for scalability, let’s go demo the app!

Step 2 – Running the Sample APP

Now for the fun part. In the previous step 1, you configured the AWS resources you needed, built the sample app project code, and downloaded it to your Mac. At the end of this walkthrough, we’ll go into how Mobile Hub guides you in integrating these features into your own app.

For now, we’ll now describe how to open the sample project code in Xcode and run the iOS sample app on a physical iOS device or simulator. It’s that simple.

The iOS sample app provides a demo for retrieving files from your S3 bucket and uploading photos from your iOS device photo library. Mobile Hub has placed a sample image to get started.

1) Unzip the iOS Swift project code you downloaded previously

step2-1

2) Open the sample app project in Xcode by double-clicking on the Xcode project, MySampleApp.xcodeproj, which is in the project folder.

3) Select build/run within Xcode to build and run the sample app.

When the sample app is first launched, a function called is called to retrieve an ID generated by the Amazon Cognito Identity service. The function invokes that manages access to Amazon Cognito. The following method illustrates how to retrieve an app user’s identity

4) At the main screen of the sample app, select User Data Storage and then Demo User File Storage feature.

step2-4a     step2-4b

You are now in the User File Storage demo and you’ll see example-image.png, which Mobile Hub provided to get started. You can now download the example image from Amazon S3 to your device.

5) To download an image from the list, select the file and then choose Download from the action item list as shown.

step2-5

Here’s the sample function that is used to download files from Amazon S3 to the mobile app.

You should now see a green check mark next to the example image, which indicates that it has been downloaded from Amazon S3 and cached locally in the app.

Now you can upload an image to Amazon S3 from your camera roll.

6) To upload a photo from your photo library to Amazon S3, select the action icon on the upper right of the screen and then choose Upload from within the User File Storage demo of the sample app.

user-storage-upload-1

7) The app will request access to your photo library. Select OK.

step2-7

8) Now the app has access to your camera roll and you can select a photo to upload to Amazon S3. Here, you can select a waterfall image.

step2-8

9) After you select an image, you are prompted to give your file a name. Give it a name and make sure you add .png to the end as shown so the app can recognize this as an image. Select Done and you’ll see the activity indicating the image is being uploaded to Amazon S3.

step2-9a   step2-9b

After the image upload completes, it’ll show in the list but without the green check mark, which indicates it’s now in the cloud (stored in your S3 bucket) but not cached locally in the app.

Here’s the sample iOS Swift function code used for uploading images from your app to Amazon S3.

What did we just do?
We just provisioned AWS backend resources consisting of an Amazon Cognito ID and Amazon S3 bucket using AWS Mobile Hub. We then built and launched the generated sample app. The app demonstrates the User Data Storage feature by uploading photos from your iOS device to Amazon S3 and downloading photos from Amazon S3 to your iOS device.

Are you done playing? We hope you enjoyed this tutorial. Stay tuned for the next installment where we’ll build on this idea and add user sign-in for more private storage and user data sync.

Are you interested in looking behind the curtain? To see that image you uploaded in the S3 bucket that was created for you, choose the Resources button on the left-hand navigation of the Mobile Hub console, choose the link in the tile labeled Amazon S3 buckets to open the Amazon S3 console, then choose the Public folder.

Planning to integrate this feature into your own app? No problem! In step 3, next, we’ll walk you through the Mobile Hub integration guide, helping you integrate all the code from the sample app into your own app.

Step 3 – Store and retrieve photos from your own app

You just configured a backend file storage and ran our generated sample app to demonstrate the end-to-end functionality of this common mobile feature. However, what you really need is the same functionality in your own app. Mobile Hub provides integration instructions specific to each mobile project you create. Let’s get started.

Go back to your Mobile Hub project in the console and select Integrate. The integration instructions from Mobile Hub will first walk you through Getting Started and then describe each feature you enabled in your Mobile Hub project and how to integrate each of them into your own app.

Here’s a quick overview of Getting Started and additional instructions for integrating this project into your own application.

The Mobile Hub Getting Started integration instructions include:

Download the Mobile SDK for iOS and custom source code provided

  • The download provides the latest SDK, Mobile Hub helper code, and example source code to get you started.

  • After downloading the SDK and helper code, drag and drop the Sdk folder contained in the download into your own project within Xcode. This assumes you already have an iOS Swift project of your own; if not, create a new one and follow along.
  • Add the AWS SDKs as Embed Frameworks.
  • Add Run Script phase to your project as directed.
  • Copy the AmazonAws folder from the helper code to your project and add a group for it. This source code contains a customized helper framework that simplifies the use of all the SDKs that are required to support your project.It also contains the AWSMobileClient.swift file, which bootstraps the app and creates an identity manager to establish the user identity with Amazon Cognito.
  • Copy the AWS dictionary from the integration Info.plist into your own project Info.plist. The AWS dictionary provides the CognitoIdentity poolId and region for your project.
  • Add AWS iOS SDK dependencies, libsqlite3.tbd and libz.tbd, under Linked Frameworks and Libraries as directed.
  • Set up your Application Delegate by returning the AWSMobileClient singleton as shown:
    You are now done with the Getting Started section.

After you complete Getting Started, you can then select User Data Storage in the left panel of the integration instructions. Here, you just need to do the following:

  • Copy the AWS dictionary from the integration Info.plist into your own project Info.plist. The AWS dictionary already provides all the CognitoIdentity pool IDs for your project as well as the S3 bucket and region.
  • View or copy the example upload/download source code provided. The idea is to use this code in your own UIViewController.

That’s it! You should now be able to run your own application and connect it to your AWS resources like we demonstrated using the sample app generated by AWS Mobile Hub.

Conclusion

We just configured a backend data storage feature via AWS Mobile Hub, generated a fully functional sample iOS app demonstrating uploading and downloading photos to and from S3, and then walked through integrating the client code into your own app, connecting to the same backend resources demonstrated in the sample app.

Thanks and happy coding!

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.