AWS Amplify, Cognito And React Example

December 14, 2018

Photo by Christopher Gower on Unsplash

AWS Amplify, Cognito And React Example

AWS Amplify is a high level API intended to facilitate the creation of applications that leverage various AWS services. As we saw in the previous tutorial, it takes close to an hour to build and deploy a serverless React application using the AWS CLI. Using Amplify, we can run a few commands to achieve the same ends.

In this tutorial, we’ll walk through how to get started with Amplify. More specifically, we’ll see how we can create a form that will allow users to sign-up using AWS Cognito.

First, we’ll use the create-react-app library to get started without having to configure Webpack and Babel.

create-react-app myapp

Inside the project run amplify init. You will then be prompted to create an IAM account if you haven’t already.

In order to use Amplify classes and functions inside of our app, we’ll have to install two additional libraries.

yarn add aws-amplify aws-amplify-react

To take advantage of the component that will act as a sign-up and sign-in form, we must first set up Cognito in the cloud. For those of you who are unfamiliar with Cognito, in essence it’s a identity access management service. In contrast to AWS IAM, Cognito is more geared towards the end users of your application. In other words, users register themselves as opposed to having their accounts created by a cloud admin. Similarly to IAM, you can decide who gets access to what resource by assigning roles. Cognito also supports sign-in with social identity providers, such as Facebook, Google, and Amazon.

amplify add auth

The last command defined the configuration necessary for Cognito. However, we still have to tell Amplify that we want the changes reflected in the cloud. You can do so by running amplify push.

Next, we’ll wrap our App component with withAuthenticator from the aws-amplify-react library. In doing so, the App component will only render once the user has successfully signed in. In its place will be the following form.

``` import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; import Amplify from 'aws-amplify'; import aws_exports from './aws-exports'; import { withAuthenticator } from 'aws-amplify-react'; Amplify.configure(aws_exports);

class App extends Component { render() { return (

      ![logo]({logo})
      

        Edit `src/App.js` and save to reload.
      

      [Learn React](https://reactjs.org) 
    

  

);

} }

export default withAuthenticator(App, true);


There are a few _gotchas_ when you go to sign up for the first time using the default settings.

*   You will get a verification code sent to you by email which will have to be used as a confirmation.
*   You must specify the area code of the phone number (i.e. North America: +1)
*   The password must be at least 8 characters long, include at least one symbol, number and uppercase letter.

Example:

Username: JaneDoe
Password: JaneDoe123!
Phone number: +15555555555
Email:


We can run configure static website hosting for our application by running:

amplify add hosting


When adding the hosting service, you’ll be prompted to select between _development_ and _production_.

*   DEV: only S3 static web hosting
*   PROD: S3 and CloudFront

The key difference is that production makes use of CloudFront to setup a content distribution network (CDN). A CDN is simply a collection of servers that deliver web content to users based off geographical location. In addition, CloudFront has a mechanism for protecting the website against DDOS attacks.

_Note:_ _When using the_ **_PROD_** _option there could be a 15–20 minute delay for the CDN setup and content replication across different regions._

In addition to updating your backend services, `amplify publish` will build your project, upload it to an S3 bucket and setup static website hosting.

Although the `withAuthenticator` component is easy to use, it provides very little flexibility. In the proceeding section we’ll create our own form using regular html elements which can be styled using CSS.

As you write code, I suggest running the application locally to avoid having to publish every time you make a change.

yarn start


The `Auth` class from the `aws-amplify` library provides asynchronous functions for signing up and in.

import React, { Component } from ‘react’; import { Auth } from ‘aws-amplify’;

class SignInForm extends Component { constructor(props) { super(props);

    this.state = {
        user: '',
        password: '',
        signedIn: false
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.signIn = this.signIn.bind(this);
    this.confirmSignIn = this.confirmSignIn.bind(this);
}

signIn() {
    const { username, password } = this.state;  
    Auth.signIn({
        username: username,
        password: password
    })
    .then(() => console.log('successfully signed in'))
    .catch((err) => console.log(`Error signing in: ${ err }`))
}

confirmSignIn() {
    const { username } = this.state;
    Auth.confirmSignIn(username)
    .then(() => console.log('successfully confirmed signed in'))
    .catch((err) => console.log(`Error confirming sign up - ${ err }`))
}

handleSubmit(e) {
    e.preventDefault();

    this.signIn();
    this.confirmSignIn()
    this.setState({
        username: '',
        password: '',
        signedIn: true
    });
    e.target.reset();
}

handleChange(e) {
    if (e.target.id === 'username') {
      this.setState({
          username: e.target.value
      });
    } else if (e.target.id === 'password') {
      this.setState({
          password: e.target.value
      });
    }
}

render() {
  const { signedIn } = this.state;
  if (signedIn) {
      return (
          

      );
  } else {
    return (
      

        

            Username
            
            Password
            
            Sign In
        

      

    );
  }
}

}

export default SignInForm;

import React, { Component } from ‘react’; import { Auth } from ‘aws-amplify’;

class SignUpForm extends Component { constructor(props) { super(props);

    this.state = {
        username: '',
        password: '',
        phone_number: '',
        email: '',
        confirmationCode: '',
        verified: false
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.signUp = this.signUp.bind(this);
    this.confirmSignUp = this.confirmSignUp.bind(this);
}

signUp() {
    const { username, password, email, phone_number } = this.state;  
    Auth.signUp({
        username: username,
        password: password,
        attributes: {
            email: email,
            phone_number: phone_number
        }
    })
    .then(() => {
        console.log('Successfully signed up');
    })
    .catch((err) => console.log(`Error signing up: ${ err }`))
}

confirmSignUp() {
    const { username, confirmationCode } = this.state;
    Auth.confirmSignUp(username, confirmationCode)
    .then(() => {
        console.log('Successfully confirmed signed up')
        this.props.handleSignup();
    })
    .catch((err) => console.log(`Error confirming sign up - ${ err }`))
}

handleSubmit(e) {
  const { verified } = this.state;

    e.preventDefault();

    if (verified) {
      this.confirmSignUp();
      this.setState({
         confirmationCode: '',
         username: ''
      });
    } else {
      this.signUp();
      this.setState({
        password: '',
        email: '',
        phone_number: '',
        verified: true
    });
    }
    e.target.reset();
}

handleChange(e) {
    if (e.target.id === 'username') {
      this.setState({
          username: e.target.value
      });
    } else if (e.target.id === 'password') {
      this.setState({
          password: e.target.value
      });
    } else if (e.target.id === 'phone_number') {
      this.setState({
          phone_number: e.target.value
      });
    } else if (e.target.id === 'email') {
      this.setState({
          email: e.target.value
      });
    } else if (e.target.id === 'confirmationCode') {
      this.setState({
          confirmationCode: e.target.value
      });
    }
}

render() {
  const { verified } = this.state;
  if (verified) {
      return (
          

              

                  Confirmation Code
                  
                  Confirm Sign up
              

          

      );
  } else {
    return (
      

        

            Username
            
            Password
            
            Phone Number
            
            Email
            
            Sign up
        

      

    );
  }
}

}

export default SignUpForm;

import React, { Component } from ‘react’; import logo from ‘./logo.svg’; import ‘./App.css’; import Amplify from ‘aws-amplify’; import aws_exports from ‘./aws-exports’; import SignInForm from ‘./SignInForm’; import SignUpForm from ‘./SignUpForm’; Amplify.configure(aws_exports);

class App extends Component { constructor(props) { super(props); this.state = { signedUp : false } this.handleSignup = this.handleSignup.bind(this); }

handleSignup() {
    this.setState({
        signedUp: true
    });
}
render() {
    const { signedUp } = this.state;
    return !signedUp ?  : ;
}

}

export default App;


Once you’ve managed to sign-up and sign-in, you can update the content of the S3 bucket by running `yarn publish`.

If you’re like me and want to avoid incurring any additional costs, you can delete all the resources associated with your project by running `amplify delete`.

[**Cory Maklin**  
_Sign in now to see your channels and recommendations!_www.youtube.com](https://www.youtube.com/channel/UCXewmpPZD3hw1uMSjXpk9Fw "https://www.youtube.com/channel/UCXewmpPZD3hw1uMSjXpk9Fw")[](https://www.youtube.com/channel/UCXewmpPZD3hw1uMSjXpk9Fw)
  

Profile picture

Written by Cory Maklin Genius is making complex ideas simple, not making simple ideas complex - Albert Einstein You should follow them on Twitter