This is a React application demonstrating how to use the AWS IoT platform via MQTT over the WebSocket protocol to build a live chat application. The sample application serves as a starting point for users to build serverless projects with Amazon Cognito, AWS Lambda and Amazon DynamoDB. The project showcases the solution to common user questions such as how to authenticate IoT devices with Amazon Cognito.
- Features
- AWS Services Showcased
- Installation
- Application Walkthrough
- Architecture Walkthrough
- Testing
- Register user
- Login / Logout
- Create room
- Join room
- Real-time chat
- Unread message indicators
- AWS IoT to exchange messages between web clients
- Transmit messages using the MQTT over the WebSocket protocol to reduce network bandwidth requirements
- Authenticate clients with Amazon Cognito and attach IoT policies to allow clients to:
- Connect to the AWS IoT Device Gateway
- Publish messages to specific topics
- Subscribe & receive messages from specific topics
- Authentication with Amazon Cognito User Pools and Cognito Federated Identities
- Serverless computing with AWS Lambda
- API access control provided by Amazon API Gateway
- Room persistence via Amazon DynamoDB
- Static site hosting on Amazon S3
- Amazon CloudFront as a proxy and CDN
Prerequisites:
Please note that this project has only been tested on macOS. Windows users may need to update some of the scripts. Pull requests are welcome to add Windows support.
- Install and configure the AWS Command Line Interface
- Ensure that the aws cli region is the same as what you define in
api/config.yml
- Please configure your
output
format to bejson
. Instructions
- Ensure that the aws cli region is the same as what you define in
- jq to process command-line JSON.
- npm the node package manager
- Clone the repository
$ git clone https://github.com/aws-samples/aws-iot-chat-example.git
- Deploy the backend
If you would like to enable login with Facebook and/or Google, please follow the Social Logins guide.
$ cd api
$ sudo npm install -g serverless
$ npm install
$ serverless deploy
The Serverless Framework is a tool for deploying serverless architectures. The stack including Lambda functions and CloudFormation resources are defined in api/serverless.yml
.
After deploying the serverless application, two scripts are invoked by means of a lifecycle hook. The first, api/scripts/attachConfirmUserTrigger.sh
is used to attach a Lambda function to the PreSignUp trigger on the Cognito User Pool.
The second script in client/scripts/setup.sh
uses the AWS CLI to query the Cloudformation template output variables and stores them in the file client/src/config/config.json
. This auto-generated file is then imported by client/src/config/index.js
and used within the client side application.
- Run the frontend client
$ cd ../client
$ npm install
$ npm start
It is important to run the setup script so that the client knows the destination of the AWS IoT endpoint, API Gateway endpoint and other coniguration variables generated by serverless deploy
.
- Open
http://localhost:3000
and try it out!
To tear down the stack, use the command serverless remove
.
Try the app on the Demo website
- Register Page
/register
Register a user using Amazon Cognito User Pools. You can use user pools to add user registration and sign-in features to your apps.
- Login page
/login
Login a user using Amazon Cognito User Pools.
Alternatively, you can use Amazon Cognito Federated Identities to create unique identities for your users and federate them with identity providers such as Facebook and Google.
- Rooms List
/app/rooms
Displays the list of available rooms to join. If you are subscribed to a room, there will be an icon indication. The number of unread messages to subscribed rooms is also displayed. Lastly, on this screen you can create a room. The application will generate an appropriate topic name to publish on if your room name contains illegal characters.
All HTTP API endpoints are AWS Lambda functions invoked through Amazon API Gateway.
- Room
/app/room/public/bad-programming-jokes
This is the main chat page where the real-time messaging is displayed. You will still be subscribed to other rooms as indicated by the unread message counters that increment when a message is received. Sending a message will dispatch a message to AWS IoT which in turn is responsible for fanning out the messages to all the subscribers of the room.
- The client-side code is a React application.
- The project was bootstrapped using create-react-app.
- The project is written in Javascript using ES6 syntax and compiled using Babel.
- Redux is used for state management
- Semantic UI React is the UI library
- React Router is handles app navigation
- AWS SDK for JavaScript as the AWS client library
- AWS IoT Device SDK for JavaScript as the MQTT client
To deploy the backend, this project uses the Serverless Framework which is backed by AWS CloudFormation. In the api/serverless.yml
file, functions, events, resources and services are defined which Serverless uses to deploy the appropriate Lambda functions, API Gateway services and additional CloudFormation resources.
MQTT (Message Queue Telemetry Transport) protocol uses a hierarchical structure to describe the topic space. Multi-level #
wildcards and single-level +
wildcards can be used in addition to topic level separators /
.
In this application, topics are subscribed to using the form:
room/public/:roomName/+
This matches topics such as:
room/public/room/abc
room/public/another-room/123
room/public/another-room/us-west-2:7f86d9a8-b9f4-439e-bcf3-9756e4d2bbdf
Note the last example topic because this is the topic that users will publish to.
room/public/:roomName/:cognitoIdentityId
Based on the MQTT specification, a receiving client does not know who published the message without either including the message author in the message payload itself or by encoding the message author in the message topic.
This application opted for the second option by appending the cognito identity id to the end of the publishing topic. To prevent users from publishing to other user's topics, the AWS Lambda function AttachPublicPublish
creates a dynamic IoT policy that allows only that one identity to publish messages to their unique topic.
- See Authentication Tutorial for an guide on configuring the user pools, identity pools and IoT policies.
- See Auto Confirming Users Guide to show how to build a registration flow without MFA
- See Social Logins Guide for information on how to enable Facebook and Google login flows
- See Mobile Hub Deployment Guide to learn how to deploy the application to an S3 bucket and distribute it via Amazon CloudFront's global network of edge cache servers.
In both the api
and client
directories, npm run test
can be used to run unit tests using jest