Allow Users to Change Passwords
For our Serverless notes app, we want to allow our users to change their password. Recall that we are using Cognito to manage our users and AWS Amplify in our React app. In this chapter we will look at how to do that.
For reference, we are using a forked version of the notes app with:
- A separate GitHub repository: https://github.com/AnomalyInnovations/serverless-stack-demo-user-mgmt-client
- And it can be accessed through: https://demo-user-mgmt.serverless-stack.com
Let’s start by editing our settings page so that our users can use to change their password.
Add a Settings Page
Replace the return
statement in src/containers/Settings.js
with.
return (
<div className="Settings">
<LinkContainer to="/settings/email">
<LoaderButton block bsSize="large">
Change Email
</LoaderButton>
</LinkContainer>
<LinkContainer to="/settings/password">
<LoaderButton block bsSize="large">
Change Password
</LoaderButton>
</LinkContainer>
<hr />
<Elements
stripe={stripePromise}
fonts={[
{
cssSrc:
"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800",
},
]}
>
<BillingForm isLoading={isLoading} onSubmit={handleFormSubmit} />
</Elements>
</div>
);
And import the following as well.
import { LinkContainer } from "react-router-bootstrap";
import LoaderButton from "../components/LoaderButton";
All this does is add two links to a page that allows our users to change their password and email.
Replace our src/containers/Settings.css
with the following.
@media all and (min-width: 480px) {
.Settings {
padding: 60px 0;
margin: 0 auto;
max-width: 480px;
}
.Settings > .LoaderButton:first-child {
margin-bottom: 15px;
}
}
Change Password Form
Now let’s create the form that allows our users to change their password.
Add the following to src/containers/ChangePassword.js
.
import React, { useState } from "react";
import { Auth } from "aws-amplify";
import { useNavigate } from "react-router-dom";
import { FormGroup, FormControl, FormLabel } from "react-bootstrap";
import LoaderButton from "../components/LoaderButton";
import { useFormFields } from "../lib/hooksLib";
import { onError } from "../lib/errorLib";
import "./ChangePassword.css";
export default function ChangePassword() {
const nav = useNavigate();
const [fields, handleFieldChange] = useFormFields({
password: "",
oldPassword: "",
confirmPassword: "",
});
const [isChanging, setIsChanging] = useState(false);
function validateForm() {
return (
fields.oldPassword.length > 0 &&
fields.password.length > 0 &&
fields.password === fields.confirmPassword
);
}
async function handleChangeClick(event) {
event.preventDefault();
setIsChanging(true);
try {
const currentUser = await Auth.currentAuthenticatedUser();
await Auth.changePassword(
currentUser,
fields.oldPassword,
fields.password
);
nav("/settings");
} catch (error) {
onError(error);
setIsChanging(false);
}
}
return (
<div className="ChangePassword">
<form onSubmit={handleChangeClick}>
<FormGroup bsSize="large" controlId="oldPassword">
<FormLabel>Old Password</FormLabel>
<FormControl
type="password"
onChange={handleFieldChange}
value={fields.oldPassword}
/>
</FormGroup>
<hr />
<FormGroup bsSize="large" controlId="password">
<FormLabel>New Password</FormLabel>
<FormControl
type="password"
onChange={handleFieldChange}
value={fields.password}
/>
</FormGroup>
<FormGroup bsSize="large" controlId="confirmPassword">
<FormLabel>Confirm Password</FormLabel>
<FormControl
type="password"
onChange={handleFieldChange}
value={fields.confirmPassword}
/>
</FormGroup>
<LoaderButton
block
type="submit"
bsSize="large"
disabled={!validateForm()}
isLoading={isChanging}
>
Change Password
</LoaderButton>
</form>
</div>
);
}
Most of this should be very straightforward. The key part of the flow here is that we ask the user for their current password along with their new password. Once they enter it, we can call the following:
const currentUser = await Auth.currentAuthenticatedUser();
await Auth.changePassword(currentUser, fields.oldPassword, fields.password);
The above snippet uses the Auth
module from Amplify to get the current user. And then uses that to change their password by passing in the old and new password. Once the Auth.changePassword
method completes, we redirect the user to the settings page.
Let’s also add a couple of styles.
@media all and (min-width: 480px) {
.ChangePassword {
padding: 60px 0;
}
.ChangePassword form {
margin: 0 auto;
max-width: 320px;
}
}
Let’s add our new page to src/Routes.js
.
<AuthenticatedRoute exact path="/settings/password">
<ChangePassword />
</AuthenticatedRoute>
And import it.
import ChangePassword from "./containers/ChangePassword";
That should do it. The /settings/password
page should allow us to change our password.
Next, let’s look at how to implement a change email form for our users.
For help and discussion
Comments on this chapter