Create a simple OTP system using AWS Serverless services
Tags: aws, serverless, otp
Published: 2023-06-26 20:30:03

# Intro
In this article, we wil look at how to use AWS Serverless services to set up a basic One-Time Password (OTP) system, which may be used as part of two-factor authentication.


Let us list the tools and technologies used to build this application.

* <a href="https://aws.amazon.com/lambda/" target="_blank">AWS Lambda</a>
* <a href="https://aws.amazon.com/api-gateway/" target="_blank">API Gateway</a>
* <a href="https://aws.amazon.com/dynamodb/" target="_blank">DynamoDB</a>
* <a href="https://aws.amazon.com/ses/" target="_blank">Simple Email Service - SES</a>
* <a href="https://aws.amazon.com/amplify/hosting/" target="_blank">Amplify Web Hosting</a>
* <a href="https://vuejs.org/" target="_blank">VueJS</a> for frontend
* Deploy with <a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html" target="_blank">AWS SAM</a>

# Architecture

![text](https://github.com/apotitech/photos_document_md/raw/master/src/common/photos/ARCH1.png "text")

# How it works
In this scenario, we will use a login form **built with VueJS** and ***hosted*** with **Amplify static web hosting**.

1. After the user enters their email and password, an API endpoint is contacted to perform the "`Generate OTP`" **Lambda function**, which generates a **6-digit** code along with a `session id`.
2. "`Generate OTP`" Lambda will save the code and `session id` into a `DynamoDB` table after they are generated.
3. The API endpoint will then return simply the `session id` as a response.
4. The table has DynamoDB streams enabled. As a result, once the data is stored, the "Send Email" Lambda function is called.
5. The "`Send Email`" **Lambda function** will use the `Simple Email Service` (SES) to send an email containing the created code to the specified email address.

6. Meanwhile, once the `session id` is retrieved from the API, a second form is offered to enter the code, which is then emailed to the specified address.

7. When the user enters and submits the code, it will confirm it along with the `session id` using another API gateway endpoint that will proxy to the "`Verify OTP`" **Lambda function**.

8. The **Lambda function** "`Verify OTP`" queries the `DynamoDB` table with the specified `session-id` and code and returns success or error results.



# Key points/Lessons learned

1. In this case, I set `DynamoDB` TTL to delete the entries after a certain amount of time to avoid rapidly filling the table. When the TTL expires, `DynamoDB` will not destroy your record instantly. It is finally erased, however AWS only guarantees that it will be deleted within 48 hours. As a result, while checking the OTP code, it must take into account the same "`expiredAt`" parameter that was used to set the TTL.

2. To conveniently query the required data, I used sessionId + OTP code as a primary key when designing the `DynamoDB` table. So, when testing the code, I query the `DynamoDB` table by primary key with this combination.

3. When you use `DynamoDB` stream as a trigger for Lambda, it receives triggers for all `DynamoDB` events (for example, insert, delete, and update). So, within the **Lambda function**, I had to filter out only the INSERT events using the record's "eventName."

4. I used AWS's own `Simple Email Service` (SES) to send emails. To send emails to any address, you must first validate your sending email address. This can be accomplished through a support request.

5. To host the application's `frontend`, I used Amplify static web hosting. I used Amplify capabilities such as auto deploys when the `Github repository` is amended and setting up a custom domain name with a few button clicks.

6. I deployed the **backend** resources using `AWS SAM`. At the time of deployment, the expiry period of the `OTP` and the number of digits in the `OTP` code can be set.


# How to set up
##### Prerequisites
* AWS CLI
* AWS SAM CLI
* Set up and verified SES send email address


## Backend
#### 1. Clone the repository
```bash
git clone https://github.com/pubudusj/simple-otp
```

#### 2. Run
```bash
sam init && sam deploy -g
```

The stack's backend will be created once you enter your stack details and AWS environment parameters. Take note of the `ApiBaseUrl` that is returned (copy it).

## Frontend
1. Copy the `.env.example` into `.env` file. Now add the `ApiBaseUrl` value as `VUE_APP_API_BASE_URL`.

2. You can either **manually** deploy the application to your `Amplify web hosting` environment, or authorize your GitHub repository to do so automatically with every git push.

3. The frontend can be executed locally by navigating to the frontend directory and then running the command `run npm server`.


##### To Delete the stack
To **delete the backend**, run the command
```bash
sam delete
```

### Demo
Demo version of this application is available at :

> https://simple-otp.pubudu.dev/

## Feedback
Your valuable feedback on this project is mostly welcome! I would like you to play around with this and if you have any questions or general comments, please reach out to me via Personal Blog, LinkedIn, Twitter or Github.

> Thank you for taking the time to read this! Your valuable feedback on this project is mostly welcome! I would like you to play around with this and if you have any questions or general comments, please reach out to me on [LinkedIn](https://www.linkedin.com/in/apotitech-b79097210/) and [Medium](https://medium.com/@softwaresennin) to so we can talk more about it. 😅