Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comments: Signup with AWS Cognito #46

Closed
jayair opened this issue Apr 10, 2017 · 37 comments

Comments

Projects
None yet
@jayair
Copy link
Member

commented Apr 10, 2017

@jayair jayair added the Discussion label Apr 10, 2017

@DushyantShukla

This comment has been minimized.

Copy link

commented Sep 5, 2017

Is this code functional? As I was unable to register a new user. I found that the email attribute should be passed against the key email in the userAttributes parameter of SignUp API. Finally, below is my updated signup() method which works just fine:

signup(email, password) {
        const userPool = new CognitoUserPool({
            UserPoolId: config.cognito.USER_POOL_ID,
            ClientId: config.cognito.APP_CLIENT_ID
        });
        const attributeList = [];
        attributeList.push(new CognitoUserAttribute({
            Name: 'email',
            Value: email
        }));
        return new Promise((resolve, reject) =>
            userPool.signUp(email, password, attributeList, null, (err, result) => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(result.user);
            })
        );
    }
@jayair

This comment has been minimized.

Copy link
Member Author

commented Sep 5, 2017

@DushyantShukla Yeah it is functional. The tutorial has been updated so that the email can be passed in as the username. You can read more about the update here - #123.

If you need to reference the old version of the tutorial, there is a hosted version here - https://59a70f2ccf321c2ccb15113f--serverless-stack.netlify.com.

@DushyantShukla

This comment has been minimized.

Copy link

commented Sep 6, 2017

Oops! Didn't know that! I appreciate the response. Thanks!

@QuantumInformation

This comment has been minimized.

Copy link

commented Oct 8, 2017

When a user signs up I get this screen

image

But I get an email link instead:

image

which takes me to this page

image

@QuantumInformation

This comment has been minimized.

Copy link

commented Oct 9, 2017

I rechecked my pool with the advice in https://serverless-stack.com/chapters/create-a-cognito-user-pool.html but it seems the same to me.

@jayair

This comment has been minimized.

Copy link
Member Author

commented Oct 9, 2017

@QuantumInformation Hmm can you check this setting?

screen shot 2017-10-09 at 7 06 20 pm copy

It should have defaulted to Code instead of Link.

@elnbado

This comment has been minimized.

Copy link

commented Oct 12, 2017

In handleSubmit = async event =>

I get the following Warning when calling:

  this.setState({
        newUser: newUser
  });


Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.

Please check the code for the Signup component.

Anyone else has this problem? Any ideas to resolve this?

@jayair

This comment has been minimized.

Copy link
Member Author

commented Oct 12, 2017

@elnbado This happens usually when you make the setState call after you move away from the page. Is your app redirecting after you hit the Signup button?

@millergd

This comment has been minimized.

Copy link

commented Oct 20, 2017

For some reason, my signup() method did not work until I added an attribute list to the userPool.signUp() call. Is this out of date?

this is what my working code looks like:

signup(email, password) {
        const userPool = new CognitoUserPool({
            UserPoolId: config.cognito.USER_POOL_ID,
            ClientId: config.cognito.APP_CLIENT_ID
        });
        const attributeList = [];
        attributeList.push(new CognitoUserAttribute({
            Name: 'email',
            Value: email
        }));
        return new Promise((resolve, reject) =>
            userPool.signUp(email, password, attributeList, null, (err, result) => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(result.user);
            })
        );
    }
@jayair

This comment has been minimized.

Copy link
Member Author

commented Oct 20, 2017

@millergd The tutorial had been updated a while back to set the email as the username in the User Pool. This makes it so that you don't have to set the attribute. You can read more about it here - #123.

@millergd

This comment has been minimized.

Copy link

commented Oct 20, 2017

@jayair yeah it looks like I was using an older version of the tutorial and setting up the userpool different.

However, I don't really understand the changes. Can you clarify what was the norm before and after the update?

Previously, we were manually setting using the email as a user’s username. There is one major issue
with this; the username cannot be changed in your Cognito User Pool. AWS fixed this by adding the
option of using the email as the username while logging in and signing up. 
@jayair

This comment has been minimized.

Copy link
Member Author

commented Oct 20, 2017

@millergd Yeah the issue with setting the email as the username manually (as we were doing before) was that the username in Cognito cannot be changed. So you would need to work around this in case your users need to change their email.

But with the new email as username setting that's been introduced recently, the User Pool sets a unique string as the username internally. This allows you to change a user's email (and username) easily.

Hopefully that makes sense. It is a bit confusing though.

@d0ruk

This comment has been minimized.

Copy link

commented Jan 4, 2018

@jayair

setting the email as the username manually

Can you elaborate on this? Did you use to derive a dummy username from the email?

I am using aws-amplify for Auth. Signature of the signUp function is

signUp(username: string, password: string, email: string, phone_number: string): Promise

I have to supply a username. So I derive a username from the email, and do signUp(dummyName, password, email). However, this way, the user gets a username she doesn't even see. It's some specific way of string manipulation my client does.

Thus, when the user logs in via her email, that same util function derives the same username, and makes the request to the user pool with that. So the e-mail is really not needed, the way I went about doing it.

Did you have to do it like the above? Make up a username?


p.s. From the looks of this PR, the new signature will be;

signUp(username: string, password: string, email: string|Array<Object>, phone_number: string): Promise<any>

I think that will allow you to attach custom attributes to your user. However, that still seems to necessitate a username.

p.p.s When I try to signup with email in place of the username, AWS returns

Username cannot be of email format, since user pool is configured for email alias.

Which is cryptic to me. When I try to verify the user, I again need to supply the derived username.

However, when logging in, I can use the e-mail address as is, apparently. So, the username is used only for the signup phase? I don't need it afterwards?

@jayair

This comment has been minimized.

Copy link
Member Author

commented Jan 5, 2018

@d0ruk We were setting the username manually. As in passing in the email as the username. The error you are getting is because you have the email as alias option enabled. This means users can login with either their username or email. But it does not allow usernames that are of the email format since you could have an unverified email as the username. In the tutorial we don't use this option.

@d0ruk

This comment has been minimized.

Copy link

commented Jan 5, 2018

@jayair

Thus, if I don't use any aliases, would the user pool accept signup/login flows with an email? As I linked above, the signUp() method requires a username.

I'm asking this because there might not be such an option in the aws-amplify API, yet. Cognito might be supportting it, however. I'm trying to discern what is possible with aws-amplify.

@jayair

This comment has been minimized.

Copy link
Member Author

commented Jan 8, 2018

@d0ruk Yeah I'm not sure about amplify. Are you not able to change the User Pool settings from the AWS Console?

@d0ruk

This comment has been minimized.

Copy link

commented Jan 9, 2018

@jayair

I'm trying to figure out the .yaml representation of the userpool in the tutorial. That's outside the scope of the book.

I'll leave it as is (derive username for login/verify) since it works. I'll note it somewhere here in case this turns out to be a no-no with aws-amplify.

Cheers.

@PraneshBalekai

This comment has been minimized.

Copy link

commented Feb 5, 2018

Is there a link/reference to how to register the user with an Identity pool after sign up?

@jayair

This comment has been minimized.

Copy link
Member Author

commented Feb 5, 2018

@PraneshBalekai What do you mean by registering a user with an Identity Pool?

@PraneshBalekai

This comment has been minimized.

Copy link

commented Feb 6, 2018

@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

@jayair

This comment has been minimized.

Copy link
Member Author

commented Feb 9, 2018

@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.

@navinc

This comment has been minimized.

Copy link

commented Feb 24, 2018

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

@grundmanise

This comment has been minimized.

Copy link
Contributor

commented Mar 10, 2018

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;
@jayair

This comment has been minimized.

Copy link
Member Author

commented Mar 13, 2018

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

@viccooper142

This comment has been minimized.

Copy link

commented Apr 8, 2018

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!

@EllaVader

This comment has been minimized.

Copy link

commented Apr 8, 2018

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});
    }
  }

notafunction

@jayair

This comment has been minimized.

Copy link
Member Author

commented Apr 9, 2018

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

@jayair

This comment has been minimized.

Copy link
Member Author

commented Apr 9, 2018

@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.

@viccooper142

This comment has been minimized.

Copy link

commented Apr 9, 2018

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
        },
      ]
    }
  });
@jayair

This comment has been minimized.

Copy link
Member Author

commented Apr 9, 2018

@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?

@viccooper142

This comment has been minimized.

Copy link

commented Apr 9, 2018

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

@EllaVader

This comment has been minimized.

Copy link

commented Apr 9, 2018

@jayair thank you -- I missed that typo

@ghost

This comment has been minimized.

Copy link

commented Apr 22, 2018

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.

screen shot 2018-04-21 at 8 42 19 pm

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>
        );
    }
}
@jayair

This comment has been minimized.

Copy link
Member Author

commented Apr 22, 2018

@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?

@ghost

This comment has been minimized.

Copy link

commented Apr 22, 2018

@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"
  }
}
@jayair

This comment has been minimized.

Copy link
Member Author

commented Apr 23, 2018

@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.

@jayair jayair closed this May 9, 2018

@jayair jayair reopened this May 9, 2018

@jayair

This comment has been minimized.

Copy link
Member Author

commented May 9, 2018

@jayair jayair closed this May 9, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.