AWS Mobile Blog

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

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

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

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

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

PREREQUISITES

IAM User

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

Deploying ASP.NET on AWS

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

AWS Toolkit for Visual Studio

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

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

Setting up Amazon Cognito

Set up the User Pool

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

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

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

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

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


Figure 2: Enable ADMIN_NO_SRP_AUTH

Overview of C# Configuration and Code

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

Web.CONFIG SETUP

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

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

Figure 3: Required Web.config settings

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

User Registration and Confirmation

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

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

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

        . . . 
    }

Figure 4: Instantiating the AmazonCognitoIdentityProviderClient

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

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

Figure 5: Basic user object.

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

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

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

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

            };

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

            return _client.SignUpAsync(signUpRequest);
        }
    }

Figure 6: Create a user identity with SignUpAsync()

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

Figure 7: Manual confirmation of the user.

USER Authentication

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

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

    public class CognitoUserManager : UserManager<CognitoUser>
    {

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

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

	 . . .

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

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

                AdminInitiateAuthResponse authResp = await _client.AdminInitiateAuthAsync(authReq);

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

Figure 9: Authenticating credentials with AdminInitiateAuthAsync()

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

Conclusion

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

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