> For the complete documentation index, see [llms.txt](https://atd-dts.gitbook.io/moped-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://atd-dts.gitbook.io/moped-documentation/dev-guides/authentication/react-and-cognito.md).

# React & Cognito

We use AWS Amplify to connect AWS to Cognito, and on top of this challenge we also had to have three environments: Local, Staging and Production.

### Requirement Libraries

We needed to add two libraries, one is aws-amplify and the other is env-cmd to manage our different environment and environment variables within React.

First, aws-amplify:

```
$ npm install aws-amplify --save
```

Then, env-cmd:

```
$ npm install env-cmd --save
```

## React

In the current theme we are using, we first needed to manage our environments. To do this, I’ve created a file called `.env-cmdrc` in the react root directory (the same directory package.json lives in), and it looks like this:

```
{
  "local": {
    "REACT_APP_AWS_COGNITO_REGION": "us-east-1",
    "REACT_APP_AWS_COGNITO_USER_POOL_ID": "us-east-1_U2dzkxfTv",
    "REACT_APP_AWS_COGNITO_APP_CLIENT_ID": "3u9n9373e37v603tbp25gs5fdc"
  },
  "staging": {
    "REACT_APP_AWS_COGNITO_REGION": "us-east-1",
    "REACT_APP_AWS_COGNITO_USER_POOL_ID": "us-east-1_U2dzkxfTv",
    "REACT_APP_AWS_COGNITO_APP_CLIENT_ID": "3u9n9373e37v603tbp25gs5fdc"
  },
  "production": {
    "REACT_APP_AWS_COGNITO_REGION": "us-east-1",
    "REACT_APP_AWS_COGNITO_USER_POOL_ID": "us-east-1_Zc3pNWX51",
    "REACT_APP_AWS_COGNITO_APP_CLIENT_ID": "ins01e2a8d3vd8apvnd0jv10c"
  }
}
```

As you can see, it contains the three environments that we need; however, the local and staging environments are identical. I left them both there, because there may be instances when we want to modify the local environment later on. Why are they identical? Because we are following the same patterns we followed in Vision Zero, where the VZE (the editor) when it runs locally it connects to the Staging environment.

### The Start/Build Scripts

I had to refactor the commands we use in the scripts section of package.json, so that we could specify the environments we have to load for the current session or build.

We use the command `env-cmd -e [environment]` command to specify what environment we want to load from the `.env-cmdrc` json file:

```
"scripts": {
    "start": "env-cmd -e local npm run start:local",
    "start:local": "export HTTPS=true && react-app-rewired start",
    "start:staging": "env-cmd -e staging npm run start:local",
    "start:production": "env-cmd -e production npm run start:local",
    "build": "env-cmd -e local npm run build:local",
    "build:local": "GENERATE_SOURCEMAP=false react-scripts build && cp _redirects build && cp -r build moped && mv moped build",
    "build:staging": "env-cmd -e staging npm run build:local",
    "build:production": "env-cmd -e production npm run build:local",
    [...]
```

Start:

* `start` This command activates the local environment and runs `start:local`
* `start:local` is the center of it all, it contains the commands to start the react app.
* `start:staging` activates the staging environment and runs `start:local`
* `start:production` activates the production environment and runs `start:local`
* `build` activates the local environment and runs `build:local`
* `build:local` is at the center, it contains the commands it needs to build the react app.
* `build:staging` activates the staging environment and runs `build:local`
* `build:production` activates the production environment and runs `build:local`

### AWS-Amplify & The Matx Theme

To use aws-amplify with the Matx theme, we had to make some adjustments. First, we must be aware that the theme makes use of React-Redux, and not in a complex manner, it only makes use of it in a simple way.

### 1. The configuration file

Initially, I first created a configuration file in the `./src` directory, it looks like this:

```
export default {
    apiGateway: {
        REGION: "us-east-1",
        URL: "https://tm4r2xqz3c.execute-api.us-east-1.amazonaws.com/dev/hello"
    },
    cognito: {
        REGION: process.env.REACT_APP_AWS_COGNITO_REGION,
        USER_POOL_ID: process.env.REACT_APP_AWS_COGNITO_USER_POOL_ID,
        APP_CLIENT_ID: process.env.REACT_APP_AWS_COGNITO_APP_CLIENT_ID,
    }
};
```

Please notice that **this is the first initial state and not its final**, this is only to demonstrate how the configuration loads the necessary variables for interaction with cognito:

* REGION
* USER\_POOL\_ID
* APP\_CLIENT\_ID

### 2. Include AWS Amplify in the index page

In the index page (`src/index.jsx`), aws-amplify has been included as follows:

```
// Includes the library:
import Amplify from "aws-amplify";
[...]
// Imports the configuration above:
import config from "./config";
[...]
```

After the library and configuration details have been imported, we can proceed to initialize it. In the same file, we write the following:

```
Amplify.Logger.LOG_LEVEL = 'DEBUG';

Amplify.configure({
    Auth: {
        mandatorySignIn: true,
        region: config.cognito.REGION,
        userPoolId: config.cognito.USER_POOL_ID,
        identityPoolId: config.cognito.IDENTITY_POOL_ID,
        userPoolWebClientId: config.cognito.APP_CLIENT_ID
    },
    API: {
        endpoints: [
            {
                name: "testApi",
                endpoint: config.apiGateway.URL,
                region: config.apiGateway.REGION
            }
        ]
    }
});
```

Again, this is not permanent code and this only serves as a demonstration of how the code can work. It should be also helpful to mention that `LOG_LEVEL` is optional, it’s there for us to see what the library is doing and it may be helpful when debugging in local or staging development.

### 3. The jwtAuthService.js file

The Matx theme makes use of React-Redux, and its patterns make use of a file called `src/app/services/jwtAuthService.js`. This file controls the gathering of a token and creating a user session.

It’s a class that has a few methods, one of them is called `loginWithEmailAndPassword` and its code is something like this:

```
loginWithEmailAndPassword = (email, password) => {
    return Auth.signIn(email, password).then(data => {
      localStorage.setItem("atd_aws_cognito_session", JSON.stringify(data));
      localStorage.setItem("atd_aws_cognito_session_payload", JSON.stringify(data.signInUserSession.idToken.payload));
      this.user = this.buildUserData(data);
      this.setSession(this.user.token);
      this.setUser(this.user);
      return this.user;
    }).catch((error) => {
      console.log(error);
      alert(error.message);
    });
  };
```

This method retrieves the the email and password, and notice the use of the class/method `Auth.signIn` which is part of the AWS-Amplify library. In here, we basically pass the same values to the library as we receive them. That method returns a promise, which allows us to implement whatever functionality we need. In this case, we call a few methods to build the session and to store the response we get back from Cognito. If there is an error, we currently show it as an alert dialog. All the code above is bound to be modified as we are in the early stages of implementation.

The theme expects the session to have a specific format, for this purpose I created a method called `buildSession` which takes the data we received from Cognito and creates a new object with the values the theme is expecting, currently it looks like this:

```
buildUserData = (awsCognitoData) => {
  return {
    role: "ADMIN",
    userId: awsCognitoData.username,
    username: awsCognitoData.username,
    email: awsCognitoData.username,
    token: awsCognitoData.signInUserSession.idToken.jwtToken,
    tokenPayload: JSON.stringify(awsCognitoData.signInUserSession.payload),
    displayName: "Authenticated User",
    photoURL: "/assets/images/face-6.jpg",
    age: 0,
  }
}
```

I expect the code to change soon, but as of the time of this writing that is what it looks like. Notice the role, username, email, photoUrl, and age fields as an example of what is required. We need to explore the theme to see what we really need, and if it is work expanding the functionality of Cognito to retrieve the extra fields or if we should retrieve those from the database.

| **Diagram owner**     | [Data & Technology Services](https://app.gitbook.com/wiki/people/team/92ec81f5-f5e6-4a9a-9376-5eeddf86962f?ref=confluence\&src=fabric) ([Sergio Garcia](https://team-1600951431491.atlassian.net/wiki/people/5f6c958d4147d600774d5e8f?ref=confluence)) |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Team**              | <ul><li><a href="https://team-1600951431491.atlassian.net/wiki/people/5f6c958d4147d600774d5e8f?ref=confluence">Sergio Garcia</a></li><li>@ Team member</li></ul>                                                                                       |
| **Informed**          | <ul><li>@ Stakeholder</li><li>@ Stakeholder</li></ul>                                                                                                                                                                                                  |
| **Status**            |                                                                                                                                                                                                                                                        |
| **Last date updated** | e.g.,24 Sep 2020                                                                                                                                                                                                                                       |
| **On this page**      | ![](https://team-1600951431491.atlassian.net/wiki/plugins/servlet/confluence/placeholder/macro?definition=e3RvYzptYXhMZXZlbD0yfG1pbkxldmVsPTJ9\&locale=en_US\&version=2)                                                                               |

| **Name**                   | **Description**                                                                                                                                                                                                        |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Operational Excellence** | The ability to run and monitor systems to deliver business value and to continually improve supporting processes and procedures.                                                                                       |
| **Security**               | The ability to protect information, systems, and assets while delivering business value through risk assessments and mitigation strategies.                                                                            |
| **Reliability**            | The ability of a system to recover from infrastructure or service disruptions, dynamically acquire computing resources to meet demand, and mitigate disruptions such as misconfigurations or transient network issues. |
| **Performance Efficiency** | The ability to use computing resources efficiently to meet system requirements, and to maintain that efficiency as demand changes and technologies evolve                                                              |
| **Cost Optimization**      | The ability to run systems to deliver business value at the lowest price point.                                                                                                                                        |

[AWS Well Architected Framework PDF](https://d1.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf)

note

## Goals

* We need to be able to log in with username and password to Cognito
* We need to be able to retrieve a token from cognito
* We need to build a session with the details provided by cognito

## Goals

* We need to be able to log in with username and password to Cognito
* We need to be able to retrieve a token from cognito
* We need to build a session with the details provided by cognito

## &#x20;Architecture

The “architecture” is quite simple in terms of functionality, we simply make use of AWS-amplify to communicate automatically with our resource instances in AWS Cognito:![](https://team-1600951431491.atlassian.net/wiki/download/attachments/393260/FrontEnd_arch.png?version=1\&modificationDate=1600971352318\&cacheVersion=1\&api=v2)

### Architecture flow

The flow is straight forward, and there is little complexity.

1. Initialize the environment variables containing the user pool id, etc.
2. Initialize the amplify class instance (in index.js)
3. Let jwtAuthService run whenever the user logs in, and build a session.
4. Utilize the session data as needed.

Other notes:

There needs to be some understanding of how the sessions data will be utilized in a granular way, as well as using it with routes.

## &#x20;Deployment strategy

The react application is built using Netlify. Netlify was configured to deploy based on two specific branches: main and production. Each branch has separate environment variables, which are located in the `.env-cmdrc` file, these variables are applied in the build command as stipulated above.

## &#x20;References and documentation

* AWS Amplify:\
  <https://docs.amplify.aws/>
* Articles & Documentation:\
  <https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html>\
  <https://docs.amplify.aws/start/getting-started/data-model/q/integration/react>\
  <https://tutorialsdojo.com/amazon-cognito/>\
  <https://serverless-stack.com/chapters/configure-aws-amplify.html>\
  <https://medium.com/swlh/react-native-authentication-using-aws-cognito-amplify-2ead9f2ee544>\
  <https://morioh.com/p/976e9bd74c37><br>
