Signup with AWS Cognito


#21

From @PraneshBalekai on Tue Feb 06 2018 09:26:29 GMT+0000 (UTC)

@jayair I want to use Federated Identities in Cognito. I already created an identity pool and added my cognito user pool as an authentication provider. However, it does not automatically register as a new identity when I call confirmRegistration or authenticateUser. I tried to follow the method as given in use case 4 of https://github.com/aws/amazon-cognito-identity-js and tried to refresh but it doesn’t work (error: missing region in config, although it was all configured). Federated Identities was not covered in this tutorial but I was wondering if there is a guide or reference to managing federated identities in a reactJS app


#22

From @jayair on Fri Feb 09 2018 18:07:23 GMT+0000 (UTC)

@PraneshBalekai We do use Federated Identities in this tutorial. We call confirmRegistration right here - https://github.com/AnomalyInnovations/serverless-stack-demo-client/blob/master/src/containers/Signup.js#L106.

It sounds like you are getting an error because it wasn’t configured properly.


#23

From @navinc on Sat Feb 24 2018 01:14:56 GMT+0000 (UTC)

Forgot Password use-case in Login/SignUp (or for ‘extra credit’) would be awesome!


#24

From @grundmanise on Sat Mar 10 2018 10:32:08 GMT+0000 (UTC)

Is there a specific reason why throughout the guide we create new CognitoUserPool on each function invocation in this and other similar functions:

signup(email, password) {
  const userPool = new CognitoUserPool({
    UserPoolId: config.cognito.USER_POOL_ID,
    ClientId: config.cognito.APP_CLIENT_ID
  });
 ...
}

IMHO it’s better to create a CognitoUserPool once and use the exported const. For example I did it in the awsLib.js:

const userPool = new CognitoUserPool({
    UserPoolId: config.cognito.USER_POOL_ID,
    ClientId:   config.cognito.APP_CLIENT_ID,
});
export default userPool;

#25

From @jayair on Tue Mar 13 2018 17:36:52 GMT+0000 (UTC)

@grundmanise In this case we create one on every click. But yeah you could make it a part of some common code.


#26

From @viccooper142 on Sun Apr 08 2018 19:47:03 GMT+0000 (UTC)

Hi Jayair, I’m getting a couple of errors I can’t figure out. When my app page loads I get a “No userPool” alert. I can login as my test user just fine but then if I switch to a new page such as http://localhost:3000/notes/new (I just finished building this per Add the Create Note Page) then I get the same message. Also it appears that I am logged out. Any idea what I might have missed? Thanks!


#27

From @EllaVader on Sun Apr 08 2018 21:44:52 GMT+0000 (UTC)

When I try to sign up and recieve my confirmation code and then enter it in I get a message saying that “Auth.confirmSIgnup is not a function” . Here i screenshot and here is my code:

handleConfirmationSubmit = async event => {
    event.preventDefault();
    this.setState({ isLoading: true });
    try{
      await Auth.confirmSignup(this.state.email, this.state.confirmationCode);
      await Auth.signIn(this.state.email, this.state.password);

      this.props.userHasAuthenticated(true);
      this.props.history.push('/');

    } catch (e) {
      alert(e.message);
      this.setState({isLoading: false});
    }
  }


#28

From @jayair on Mon Apr 09 2018 17:32:28 GMT+0000 (UTC)

@EllaVader There is a tiny typo. It is Auth.confirmSignUp.


#29

From @jayair on Mon Apr 09 2018 17:35:05 GMT+0000 (UTC)

@viccooper142 Can you check this specific line in your src/index.js https://github.com/AnomalyInnovations/serverless-stack-demo-client/blob/configure-aws-amplify/src/index.js#L12?

It looks like Amplify might be trying to create an anonymous user every time you load your page.


#30

From @viccooper142 on Mon Apr 09 2018 18:19:53 GMT+0000 (UTC)

Looks like I just had things out of order. When I copied over your version of src/index.js then the error went away. (I’m very new to JavaScript) Here is my version:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router } from "react-router-dom";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import "./index.css";
import Amplify from "aws-amplify";
import config from "./config";

ReactDOM.render(
  <Router>
    <App />
  </Router>,
  
document.getElementById("root")
);
registerServiceWorker();

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
    },
    Storage: {
      region: config.s3.REGION,
      bucket: config.s3.BUCKET,
      identityPoolId: config.cognito.IDENTITY_POOL_ID
    },
    API: {
      endpoints: [
        {
          name: "notes",
          endpoint: config.apiGateway.URL,
          region: config.apiGateway.REGION
        },
      ]
    }
  });

#31

From @jayair on Mon Apr 09 2018 18:49:31 GMT+0000 (UTC)

@viccooper142 I think it’s the order of the calls. Can you try moving the Amplify block below the imports and see if that fixes the issue?


#32

From @viccooper142 on Mon Apr 09 2018 18:52:49 GMT+0000 (UTC)

@jayair That worked! It was just the order. I copied your version of src/index.js and the error went away. Thanks!


#33

From @EllaVader on Mon Apr 09 2018 20:43:33 GMT+0000 (UTC)

@jayair thank you – I missed that typo


#34

From @Tayl0rFay on Sun Apr 22 2018 00:47:06 GMT+0000 (UTC)

Although I copied and pasted the exact code from the Signup.js in the repo, for some reason the redirect isn’t working right.

  1. I sign up
  2. Enter the confirmation code
  3. I get an alert saying “undefined”
  4. I’m logged in, but I’m not redirected from the confirmation page.

import React, { Component } from "react";
import {
  HelpBlock,
  FormGroup,
  FormControl,
  ControlLabel
} from "react-bootstrap";
import { Auth } from "aws-amplify";
import LoaderButton from "../components/LoaderButton";
import "./Signup.css";

export default class Signup extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isLoading: false,
      email: "",
      password: "",
      confirmPassword: "",
      confirmationCode: "",
      newUser: null
    };
  }

  validateForm() {
    return (
      this.state.email.length > 0 &&
      this.state.password.length > 0 &&
      this.state.password === this.state.confirmPassword
    );
  }

  validateConfirmationForm() {
    return this.state.confirmationCode.length > 0;
  }

  handleChange = event => {
    this.setState({
      [event.target.id]: event.target.value
    });
  }

  handleSubmit = async event => {
    event.preventDefault();

    this.setState({ isLoading: true });

    try {
      const newUser = await Auth.signUp({
        username: this.state.email,
        password: this.state.password
      });
      this.setState({
        newUser
      });
    } catch (e) {
      alert(e.message);
    }

    this.setState({ isLoading: false });
  }

  handleConfirmationSubmit = async event => {
    event.preventDefault();

    this.setState({ isLoading: true });

    try {
      await Auth.confirmSignUp(this.state.email, this.state.confirmationCode);
      await Auth.signIn(this.state.email, this.state.password);

      this.props.userHasAuthenticated(true);
      this.props.history.push("/");
      
    } catch (e) {
      alert(e.message);
      this.setState({ isLoading: false });
    }
  }

  renderConfirmationForm() {
    return (
      <form onSubmit={this.handleConfirmationSubmit}>
        <FormGroup controlId="confirmationCode" bsSize="large">
          <ControlLabel>Confirmation Code</ControlLabel>
          <FormControl
            autoFocus
            type="tel"
            value={this.state.confirmationCode}
            onChange={this.handleChange}
          />
          <HelpBlock>Please check your email for the code.</HelpBlock>
        </FormGroup>
        <LoaderButton
          block
          bsSize="large"
          disabled={!this.validateConfirmationForm()}
          type="submit"
          isLoading={this.state.isLoading}
          text="Verify"
          loadingText="Verifying…"
        />
      </form>
    );
  }

  renderForm() {
    return (
      <form onSubmit={this.handleSubmit}>
        <FormGroup controlId="email" bsSize="large">
          <ControlLabel>Email</ControlLabel>
          <FormControl
            autoFocus
            type="email"
            value={this.state.email}
            onChange={this.handleChange}
          />
        </FormGroup>
        <FormGroup controlId="password" bsSize="large">
          <ControlLabel>Password</ControlLabel>
          <FormControl
            value={this.state.password}
            onChange={this.handleChange}
            type="password"
          />
        </FormGroup>
        <FormGroup controlId="confirmPassword" bsSize="large">
          <ControlLabel>Confirm Password</ControlLabel>
          <FormControl
            value={this.state.confirmPassword}
            onChange={this.handleChange}
            type="password"
          />
        </FormGroup>
        <LoaderButton
          block
          bsSize="large"
          disabled={!this.validateForm()}
          type="submit"
          isLoading={this.state.isLoading}
          text="Signup"
          loadingText="Signing up…"
        />
      </form>
    );
  }

    render() {
        return (
            <div className="Signup">
                {this.state.newUser === null
                ? this.renderForm()
                : this.renderConfirmationForm()}
            </div>
        );
    }
}

#35

From @jayair on Sun Apr 22 2018 00:55:45 GMT+0000 (UTC)

@Tayl0rFay Couple of things. Can you double check that the signup actually worked by trying to login with the credentials (make sure you are logged out first)? And can you post your package.json here as well?


#36

From @Tayl0rFay on Sun Apr 22 2018 00:57:13 GMT+0000 (UTC)

@jayair Yep, I’m able to sign in

{
  "name": "notes-app-client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "amazon-cognito-identity-js": "^2.0.3",
    "aws-amplify": "^0.3.0",
    "react": "^16.3.2",
    "react-bootstrap": "^0.32.1",
    "react-dom": "^16.3.2",
    "react-router-dom": "^4.2.2",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

#37

From @jayair on Mon Apr 23 2018 17:05:26 GMT+0000 (UTC)

@Tayl0rFay One issue I see is the amazon-cognito-identity-js include. Compare it to the one we have in the tutorial - https://github.com/AnomalyInnovations/serverless-stack-demo-client/blob/master/package.json.

This might from an older version of the tutorial. I’m not sure if it’s causing the problem but you can try removing it using npm uninstall.


#38

Hey guys, I’m having some trouble figuring out how to handle users that already exist in the database, but still need to be confirmed.

Here is what my handleSubmit looks like:

  handleSubmit = async event => {
    event.preventDefault();

this.setState({
  isLoading: true
});

try {
  const newUser = await Auth.signUp({
    username: this.state.email,
    password: this.state.password,
  });

  this.setState({
    newUser
  });
} catch (e) {
  if (e.name === 'UsernameExistsException') {
    alert(
      'Looks like your email is already in our database. ' +
      'Please check your email to find the confirmation code.',
    );

    // await Auth.resendSignUp(this.state.email);

    this.setState({
      newUser: {
        username: this.state.email,
        password: this.state.password,
      },
    });
  } else {
    alert(e.message);
  }
}

this.setState({
  isLoading: false
});
  }

I’ve commented out await Auth.resendSignUp(this.state.email);, because I don’t want AWS to lock the feature. So when a user already exists in the db and hasn’t been confirmed yet, they are sent to the confirmation code screen. But when I enter a confirmation code, I get this error:

Here is what my handleConfirmationSubmit looks like:

  handleConfirmationSubmit = async event => {
    event.preventDefault();

    this.setState({ isLoading: true });

    console.log(this.state);

    try {
      await Auth.confirmSignUp(
        this.state.newUser.user.username,
        this.state.confirmationCode,
      );

      await Auth.signIn(this.state.email, this.state.password);

      this.props.userHasAuthenticated(true);
      this.props.history.push('/');
    } catch (e) {
      alert(e.message);
      this.setState({ isLoading: false });
    }
  }

Note: Confirming an account works when the account is newly created…just not when the account already exists.

Any ideas?


#39

Hmm how come when you are calling Auth.confirmSignUp it is using this.state.newUser.user.username. Should it be this.state.newUser.username instead?


#40

Was a typo, thank you! @jayair Would you know how I could check if a user is confirmed or not? I want to do a check inside of this if statement:

else if (e.name === 'UsernameExistsException') {
        // how to check if unconfirmed?
        if ('account is unconfirmed') {
          alert(
            'Looks like your account isn\'t confirmed! ' +
            'Please check your email to find the confirmation code.',
          );
          // bring up confirmation page
        } else {
          alert(
            'Looks like you already have an account! ' +
            'Please log in with your current password.',
          );
          this.props.history.push('/login');
        }
      } 

Thanks!