AWS Mobile Blog

Announcing Your User Pools in Amazon Cognito

by David Behroozi | on | Permalink | Comments |  Share

Introduction

Today, AWS launched the Beta release of a new Amazon Cognito feature, Cognito Identity User Pools, that makes it easy for you to add sign-up and sign-in functionality to your mobile and web apps. This feature provides a simple way to create and maintain your own user directory that can scale to hundreds of millions of users. You benefit from the security and privacy best practices of AWS, and retain full control of your user data. In this blog post, for brevity, we’ll walk through how to get started using iOS.  Similar blogs for Android and JavaScript have also been posted.  For full documentation please see the Amazon Cognito Developer Guide.

Integrating your Cognito Identity user pool into your app

Let’s see how to integrate this new Amazon Cognito feature in your app.

Creating your Cognito Identity user pool

From the Amazon Cognito console, click Manage your user pool and Create a user pool to create a new user pool.

  1. Provide a name for your pool. You can opt to customize the settings of your user pool by selecting the Step through settings option. However, for this blog post, we will proceed with the default option by clicking Review defaults.
  2. Next, you will create an app client. Every app and web app that accesses your pool requires an app client ID and optionally an app client secret. You can create multiple app clients for a user pool, and you typically create one per platform (i.e., iOS, Android, JavaScript). To begin this process, click Apps on the left navigation bar and then click Add an app. Enter your app name. Select Generate client secret and then click Create app and Save changes.
  3. Click Review on the left navigation bar and then click Create pool.
  4. Note your user pool id from the screen that appears. You can find the app client id and app client secret under Apps on the left navigation bar.

Using your Cognito Identity user pool in your app

The first step for your client app is to create a UserPool object to interact with the service. Using your user pool id, app client id, and app client secret from the console, create an AWSCognitoIdentityUserPool.

   //setup service config
   AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:nil];
    
   //create a pool
   AWSCognitoIdentityUserPoolConfiguration *configuration = [[AWSCognitoIdentityUserPoolConfiguration alloc] initWithClientId:@"CLIENT_ID"
                                                                                                              clientSecret:@"CLIENT_SECRET"
                                                                                                                    poolId:@"USER_POOL_ID"];
   [AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithConfiguration:serviceConfiguration userPoolConfiguration:configuration forKey:@"UserPool"];
   AWSCognitoIdentityUserPool *pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:@"UserPool"];

Now that you have created a pool, you can start signing up users.  Using a registration UI in your app, collect the necessary information from your user and call signUp:

    NSMutableArray * attributes = [NSMutableArray new];

    //Set user attributes by retrieving them from your UI.  These values are hardcoded for this example
    AWSCognitoIdentityUserAttributeType * phone = [AWSCognitoIdentityUserAttributeType new];

    phone.name = @"phone_number";
    //All phone numbers require +country code as a prefix
    phone.value = @"+15555555555";

    AWSCognitoIdentityUserAttributeType * email = [AWSCognitoIdentityUserAttributeType new];
    email.name = @"email";
    email.value = @"email@mydomain.com";

    [attributes addObject:phone];
    [attributes addObject:email];

    //set username and password by retrieving themy from your UI.  They are hardcoded in this example.
    AWSCognitoIdentityUser *user = [[pool signUp:@"username" password:@"password" userAttributes:attributes validationData:nil] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUser *> * _Nonnull task) {
        NSLog(@"Successfully registered user: %@",task.result.username);
        return nil;
    }];

Next, you will confirm the user unless the user is automatically confirmed (automatically confirming users requires you to implement an AWS Lambda function). Users are confirmed when either their email address or phone number is verified; in this scenario, users receive a verification code at their email address or via SMS on their mobile phone during the registration flow and must input the code to complete sign-up. After obtaining the verification code from your end user, call confirmSignUp:

    //replace VERIFICATION_CODE with the value the user inputs   
    [[user confirmSignUp:@"VERIFICATION_CODE"] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderConfirmSignUpResponse *> * _Nonnull task) {
        NSLog(@"Successfully confirmed user: %@",user.username);
        return nil;
    }];

Now that you have a confirmed user, authenticate and get details for the user.  First, implement the AWSCognitoIdentityInteractiveAuthenticationDelegate protocol and set the delegate for the pool.  This protocol is meant to manage your custom login UI and accept username and password information from your end user.  The protocol’s methods are only invoked if the user has never authenticated, if the user has signed out, or if the user’s refresh token (which is valid for 30 days) has expired:

    //This code goes in your AppDelegate
    pool.delegate = self;

    -(id<AWSCognitoIdentityPasswordAuthentication>) startPasswordAuthentication{
        //implement code to instantiate and display login UI here
	//return something that implements the AWSCognitoIdentityPasswordAuthentication protocol
	return loginUI;
    }

    //This code goes in your Login UI
    -(void) getPasswordAuthenticationDetails: (AWSCognitoIdentityPasswordAuthenticationInput *) authenticationInput passwordAuthenticationCompletionSource: (AWSTaskCompletionSource *) passwordAuthenticationCompletionSource {
        //using inputs from login UI create an AWSCognitoIdentityPasswordAuthenticationDetails object.
        //These values are hardcoded for this example.
        AWSCognitoIdentityPasswordAuthenticationDetails * result = [[AWSCognitoIdentityPasswordAuthenticationDetails alloc] initWithUsername:@"USERNAME" password:@"PASSWORD"];
        //set the result to continue the sign-in process
        passwordAuthenticationDetails.result = result;
    };
    
    -(void) didCompletePasswordAuthenticationStepWithError:(NSError*) error {
    dispatch_async(dispatch_get_main_queue(), ^{
        //present error to end user
        if(error){
            [[[UIAlertView alloc] initWithTitle:error.userInfo[@"__type"]
                                        message:error.userInfo[@"message"]
                                       delegate:nil
                              cancelButtonTitle:nil
                              otherButtonTitles:@"Ok", nil] show];
        }else{
            //dismiss view controller
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    });
}

Now you can get user details using getDetails:

   [[user getDetails] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserGetDetailsResponse *> * _Nonnull task) {
        AWSCognitoIdentityUserGetDetailsResponse *response = task.result;
        for (AWSCognitoIdentityUserAttributeType *attribute in response.userAttributes) {
            //print the user attributes
            NSLog(@"Attribute: %@ Value: %@", attribute.name, attribute.value);
        }
        return nil;
    }];

If you want to obtain AWS credentials to access AWS resources for your user, first associate your user pool with an identity pool using the AWS Management Console.  If you haven’t already created an identity pool, do that using the Amazon Cognito Console.  Under Authentication providers, on the Cognito tab specify your user pool id and client id.

With that association configured, getting AWS credentials in your app is as simple as providing your AWSCognitoIdentityUserPool to your AWSCognitoCredentialsProvider:

AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 identityPoolId:@"IDENTITY_POOL_ID" identityProviderManager:pool];
AWSServiceConfiguration *defaultServiceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1
        credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = defaultServiceConfiguration;

Sample Application

For a working example demonstrating the functionality described in this blog refer to the Objective-C sample on Github.

Conclusion

That is all there is to it.  Please see the docs to learn about other functionality, like setting user attributes, changing user passwords, and associating MFAs. If you have questions, please reach out to us in the AWS forums.