Business Productivity

Integrate your Identity Provider with Amazon Chime SDK Messaging

Amazon Chime SDK Messaging provides the building blocks for your client applications to take advantage of chat and other real-time messaging features. To access the Amazon Chime SDK Messaging client side, applications require temporary AWS credentials. Many developers are not familiar with how to securely provide temporary AWS credentials to client applications. This post covers how to do that for Amazon Chime SDK Messaging.

Overview of Identity Providers and getting AWS Identity and Access Management (IAM) Credentials via AWS IAM Roles

Your application likely already has an authentication process or identity provider that gives end users access to your system (such as LDAP, AD, etc). For your end users to use Amazon Chime SDK Messaging, they can exchange your app specific access token or credentials for temporary AWS credentials that enable programmatic access to the SDK. Temporary AWS credentials are made up of a AWS Secret Key, AWS Access Key, and AWS Session Token.

The process of exchanging an application specific access token for temporary AWS credentials involves assuming an AWS Identity and Access Management (IAM) role. An IAM role is a collection of IAM policies that define a set of permissions. These permissions can be coarse or fine grained; when a user assumes the role, the user has customizable permissions that specify what that user can do. For more information on IAM roles and selecting what permissions individual user’s have refer to the Amazon Chime Developer Guide IAM Role documentation.

There are two common ways for client applications to assume IAM roles. First, an end user application can assume a role by calling a backend service you run. This backend process will validate the user’s identity token or credentials, make an AssumeRole API call, and then return the temporary AWS credentials from that API call to the user’s app. We refer to this backend service as a credential exchange service.

Alternatively, if the user’s application has a standards based access token such as SAML or OIDC, an IAM role can be assumed in a serverless manner using Amazon Cognito Identity Pools. With Amazon Cognito Identity Pools, the user’s application calls Amazon Cognito directly with their access token. Amazon Cognito Identity Pool validates the access token and then returns temporary AWS credentials obtained from a pre-configured IAM role.

Which approach you choose when adding messaging functionality to your application depends on your existing application’s authentication method. Amazon Cognito Identity Pools offers a server-less solution but requires your application’s existing authentication method be standards based. In contrast, the credential exchange service described in this blog can be modified to add any custom logic you want or work with any custom authentication processes you have.

Running Examples

Let’s launch the Amazon Chime SDK Messaging demo app to see how both these approaches works. Note: Deploying this demo and receiving traffic from the demo created in this post can incur AWS charges.

Prerequisites

Deploying the Chat Demo Application

  1. Obtain AWS credentials for your AWS account
  2. Set the AWS credentials in the AWS CLI – https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.
  3. Checkout the Amazon Chime SDK samples git repository: git clone https://github.com/aws-samples/amazon-chime-sdk
  4. Go to the chat demo folder: cd amazon-chime-sdk/apps/chat
  5. Deploy the cloud formation backed: aws cloudformation create-stack --stack-name <STACKNAME> --template-body file://src/backend/serverless/template.yaml --parameters ParameterKey=DemoName,ParameterValue=<NAME_OF_DEMO> --capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND
  6. Verify and record outputs via aws cloudformation describe-stacks --stack-name <STACKNAME>. Note, it might take a minute or two for the stack to fully deploy.
  7. In the root directory apps/chat, open src/Config.js with the editor of your choice and update the each missing config with the values from the previously step
  8. Open https://localhost:9000/ in your browser.
  9. We will start with demoing the credential exchange service. Log in with the credential exchange service by selecting Credential Exchange Service on the drop down. Note the JSON example identity token or credentials. We will discuss how those work in a moment.
  10. Click Exchange Token for AWS Credentials. Now that you are logged in and have AWS credentials you can use the chat app.

Credential Exchange Service Architecture

Let’s look at how we got credentials via the Credential Exchange Service.

This credential exchange service (1) validates your user’s credentials or identity token, (2) takes a user’s universally unique id (UUID) from that identity token, and (3) assumes a role using the user’s UUID. To allow you to easily see how this works, the demo mimics the exchange process without having the identity provider or end user credentials. On the login screen we provided an empty JSON object to represent our credentials or access token. This example token is sent to the credential exchange service which does not actually validate the token. Instead it always returns access with permissions scoped to an anonymous user. An empty method called validateAuthTokenOrCredsAndReturnUser where you would put logic to validate your access token or end user credentials. This way you can quickly modify the demo to work with your own application.

The code for the credential exchange service can be found here. The three main functions are:

  1. Validate the credentials which is empty for demo purposes.
    // STEP 1: Validate your identity providers access token and return user information
    // including UUID, and optionally username or additional metadata
    function validateAuthTokenOrCredsAndReturnUser(authToken) {
        // For demo purposes this returns an anonymous user. In production place
        // your logic to validate your auth token in this method<br />const randomUserID = uuidv4();
        return {
            uuid: randomUserID,
            username: `anon-${randomUserID}`,
            metadata: null
        };
    }
  2. Assume the role using a user’s UUID. This call returns AWS credentials with permissions scoped to that user.
    	
    // STEP 2: Get AWS Creds by calling assumeRole with the user info returned
    // in step one.
    async function assumeRole(user) {
        const assumedRoleResponse = await sts.assumeRole({
        RoleArn: USER_ROLE_ARN, // Constant value set via environment variable
        RoleSessionName: `chime_${user.uuid}`,
        DurationSeconds: '3600', // 1 hour, often want to set this to the duration of access token from IdP
        Tags: [{
                Key: 'UserUUID', // parameterizes IAM Role with users UUID
                Value: user.uuid
            }]
        }).promise();
        return assumedRoleResponse.Credentials; // returns AWS Creds
    }
    
  3. Create the user in Amazon Chime. In the demo application, an optional step is included to create the Amazon Chime app instance user in this flow. An app instance user is not meant to replace users in your identity system, but is required to persist data such as message history and access to channels. As an alternative to this approach, you can create or delete app instance users when your application creates or deletes users. When creating the app instance user it is generally best to use the same UUID that your application uses to uniquely identify users.
    
    // STEP 3: Create user in Chime
    async function createChimeUser(user) {
         // Note: if user already exists createAppInstanceUser is a NOOP and returns
        // the existing user
        const createUserResponse = await chime.createAppInstanceUser({
          AppInstanceArn: APP_INSTANCE_ID,
          AppInstanceUserId: user.uuid,
          ClientRequestToken: uuidv4(),
          Name: user.displayName
        }).promise();
        return createUserResponse.AppInstanceUserArn; // returns user arn to application
    }

You can customize this logic for your needs and try it out by pasting your user’s credentials or access token in the login page. You can find more useful tips on running a credential exchange service for Amazon Chime SDK Messaging in the Amazon Chime SDK documentation.

Logging in via Amazon Cognito (User Pools)

Now let’s try out Amazon Cognito

  1. Click logout or open the demo in a new tab (http://localhost:9000/).
  2. Confirm the drop down says “Sign in with Amazon Cognito User Pools”
  3. Provide a Username and Password for the new user. The default user pool requires the password to be a minimum of 8 characters and contain at least one uppercase, lowercase, special character, and number.
  4. Click Register.
  5. Before this user can login, their account must be confirmed. The quickest way is to do this via the AWS console. Go to the Amazon Cognito console.
  6. Choose Manage User Pools.
  7. Choose the pool that you created.
  8. Choose Users and groups in the left side panel.
  9. Choose the new user whose Account Status is UNCONFIRMED.
  10. Choose Confirm user.
  11. Now that user should be able to log in. Return the the demo login page (http://localhost:9000/).
  12. Provide the username and password of the desired user.
  13. Choose Login.

Obtaining AWS Credentials via Amazon Cognito Identity Pools Architecture

What we have just demonstrated is Amazon Cognito User Pools acting as an Identity Provider (IdP). Let’s explain how this works.

If an application is using a standards based IdP, no credential exchange service code is required. Amazon has a service that runs the equivalent of a credential exchange service for you. This service is called Amazon Cognito Identity Pools. Behind the scenes it does many of the same things that the credential exchange service does including validating the access token, getting a user’s UUID from that token, and assuming an IAM role to return AWS credentials. Amazon Cognito Identity Pools support a large range of access token formats that at the time of this writing includes:

  • Public providers: Login with Amazon, Facebook, Google, Sign in with Apple.
  • Open ID Connect Providers
  • SAML Identity Providers
  • Amazon Cognito User Pools

Using Amazon Cognito Identity Pools requires a standards based identity provider. Amazon Cognito User Pools is a standards based identity provider. The Amazon Chime SDK Messaging demo uses both when selecting “Sign in with Amazon Cognito” – Amazon Cognito User Pools as its identity provider and Amazon Cognito Identity Pools to exchange the User Pool credentials for AWS credentials. It is important to reiterate that your application does not need to use Amazon Cognito User Pools as any standards based identity provider will do.

When you use Amazon Cognito to login (as described above) you first registered a user in Amazon Cognito User Pools. When logging in with that user, Amazon Cognito User Pools returned Amazon Cognito User Pools credentials that were then exchanged for AWS credentials via Amazon Cognito Identity Pools. This was all done via the AWS Amplify framework. We will not cover the exact integration details because it is well documented in multiple places, including:

  • AWS Amplify – Amplify is an AWS client library that supports platforms including IoS, Javascript, and Android. If you want to use both Amazon Cognito User Pools and Identity Pools AWS Amplify has additional documentation here.
  • Alternatively, see Amazon Cognito’s documentation to use the Amazon Cognito APIs directly without using Amplify.

Note, the demo creates Amazon Chime SDK Messaging app instance users with an Amazon Cognito Triggerthat is invoked when users are first registered in the Amazon Cognito User Pool. For a reference implementation refer to the demo code’s AWS Lambda function.

Additionally, Amazon Cognito Identity Pools parameterizes the IAM role with the user’s UUID from the “sub” field on the user’s identity token. The “sub” or subject field is a good choice for as the user’s UUID. However, if you want to use a different field for the users UUID in your application see Amazon Cognito’s Attributes for Access Control documentation.

You can find more useful tips on using Amazon Cognito Identity Pools with Amazon Chime SDK Messaging in the Amazon Chime SDK documentation.

Clean up

If you don’t want to continue to be charged for the use of the chat demo application, you can clean up by doing the following:

To delete the stack and its resources:

  1. Delete the stack by running aws cloudformation delete-stack --stack-name <STACKNAME>
  2. Delete the Amazon Chime app instance by running aws chime delete-app-instance --app-instance-arn <APP INSTANCE ARN from src/Config.js>

Conclusion

In this blog, we have demonstrated how you can use AWS IAM roles for authentication and authorization with Amazon Chime SDK Messaging This allows for customization and enablement of different use cases via IAM policies that can be fine or coarse-grained. Obtaining AWS credentials from client applications can be easily and securely done via the methods mentioned above, enabling you to add messaging and chat functionality to your application with Amazon Chime SDK Messaging.