Introduction
In the previous tutorial, we implement the crucial part of the Authentication flow. Now, we will continue with the Profile page to extend the power of our application with Change password, Reset password, Change email features.
Creating Profile Page
To handle the profile route let's open the App.js
and paste below code block.
import { BrowserRouter, Routes, Route } from "react-router-dom";import { Home } from "./components/Home";import { Signup } from "./components/Signup";import { Verification } from "./components/Verification";import { Redirect } from "./components/Redirect";import { Login } from "./components/Login";import { PrivateRoute } from "./components/PrivateRoute";import { AuthProvider } from "./contexts/Auth";import { Profile } from "./components/Profile";export default function App() { return ( <div> <BrowserRouter> <AuthProvider> <Routes> <Route path="/" element={ <PrivateRoute> <Home /> </PrivateRoute> } /> <Route path="/profile" element={ <PrivateRoute> <Profile /> </PrivateRoute> } /> <Route path="/signup" element={<Signup />} /> <Route path="/auth-redirect" element={<Redirect />} /> <Route path="/verification" element={<Verification />} /> <Route path="/login" element={<Login />} /> </Routes> </AuthProvider> </BrowserRouter> </div> );}
Here we are adding localhost:3000/profile
private route to handle the change password/reset password and change email functionalities.
So, let’s create Profile.js
component inside of the components folder to handle these functionalities.

Let’s implement all with the below code block then review them step-by-step.
import { useRef, useState } from "react";
import { useAuth } from "../contexts/Auth";
import { altogic } from "../helpers/altogic";
export function Profile() {
const oldPassword = useRef();
const newPassword = useRef();
const newEmail = useRef();
const email = useRef();
const currentPassword = useRef();
// Get current user and signOut function from context
const { setUser, setSession, user } = useAuth();
const [changePasswordResponse, setchangePasswordResponse] = useState(null);
const [resetPasswordResponse, setResetPasswordResponse] = useState(null);
const [changeEmailResponse, setChangeEmailResponse] = useState(null);
// create async function to change password
async function handleChangePassword(e) {
e.preventDefault();
// get password input values
const oldPassword = e.target.oldPassword.value;
const newPassword = e.target.newPassword.value;
// call altogic client library `changePassword` function
const changePasswordResponse = await altogic.auth.changePassword(
newPassword,
oldPassword
);
setchangePasswordResponse(changePasswordResponse);
}
// create async function to reset password
async function handleResetPassword(e) {
e.preventDefault();
// get email input value
const email = e.target.email.value;
// call altogic client library `sendResetPwdEmail` function
const resetPasswordResponse = await altogic.auth.sendResetPwdEmail(email);
setResetPasswordResponse(resetPasswordResponse);
}
// create async function to change email address
async function handleChangeEmail(e) {
e.preventDefault();
// get email and password input values
const newEmail = e.target.newEmail.value;
const currentPassword = e.target.currentPassword.value;
// call altogic client library `changeEmail` function
const changeEmailResponse = await altogic.auth.changeEmail(
currentPassword,
newEmail
);
setUser(altogic.auth.getUserFromDB());
setSession(altogic.auth.getSession());
setChangeEmailResponse(changeEmailResponse);
}
return (
<>
<div style={{ margin: "20px 20px" }}>
{/* Displays the user email */}
<p>Welcome, {user?.email} !</p>
<span>
<p>
Your email verification status:{" "}
{user?.emailVerified ? "Verified" : "Not Verified"}
</p>
</span>
<pre>{user && JSON.stringify(user, null, 3)}</pre>
{/* Change Password section */}
<div>
<h1>Change Password</h1>
<form onSubmit={handleChangePassword}>
<label>Old Password:</label>
<input type="password" name="oldPassword" ref={oldPassword} />
<label>New Password:</label>
<input type="password" name="newPassword" ref={newPassword} />
<input type="submit" value="Change Password" />
</form>
<pre>
{changePasswordResponse &&
JSON.stringify(changePasswordResponse, null, 3)}
</pre>
</div>
{/* Change Email section */}
<div>
<h1>Change Email</h1>
<form onSubmit={handleChangeEmail}>
<label>Password:</label>
<input
type="password"
name="currentPassword"
ref={currentPassword}
/>
<label>New Email:</label>
<input type="email" name="newEmail" ref={newEmail} />
<input type="submit" value="Change Email" />
</form>
<pre>
{changeEmailResponse &&
JSON.stringify(changeEmailResponse, null, 3)}
</pre>
</div>
{/* Reset Password section */}
<div>
<h1>Reset Password</h1>
<form onSubmit={handleResetPassword}>
<label>Email:</label>
<input type="email" name="email" ref={email} />
<input type="submit" value="Send Reset Password Email" />
</form>
<pre>
{resetPasswordResponse &&
JSON.stringify(resetPasswordResponse, null, 3)}
</pre>
</div>
</div>
</>
);
}

Here we are implementing handleChangePassword
, handleChangeEmail
, and handleResetPassword
functions to send request to Altogic backend.
To use the
altogic.auth.changePassword
function, the Altogic client library requiresoldPassword
andnewPassword
parameters, so to collect this information, we are implementing the useRef hook again to manage these values from the form element.Once the user enters the values and clicks the
Submit
button, Altogic changes the user password.To use the
altogic.auth.changeEmail
function, the Altogic client library requirescurrentPassword
andnewEmail
parameters, so to collect this information we are implementing the useRef hook to collect these values from the form element.Once the user enters the values and clicks the
Submit
button, Altogic will send a confirmation email to the user to click. Once the user clicks the link in the email, it navigates users to theRedirect URL
with theaction=change-email
andaccess_token
query string parameter.
To use the
altogic.auth.resetPassword
function, the Altogic client library requires onlyemail
parameter, so to collect that information, we are implementing the useRef hook to collectemail
from the form element.Once the user enters the email and clicks the
Submit
button, Altogic will send a reset password link to the user to click.When the user clicks the link in the email, it navigates users to the
Redirect URL
with theaction=reset-pwd
andaccess_token
query string parameters. At that time, we need to use this access_token with another Altogic Client library method,altogic.auth.ResetPwdWithToken
, to reset password.
Also, we need to store access_token
in the previously created Authentication context to share state across the pages.
Updating Authentication Context
Copy the following code to the Auth.js
file inside the context/
folder to store and share the access_token
state.
import React, { useContext, useState, useEffect } from "react";
import { altogic } from "../helpers/altogic";
const AuthContext = React.createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [user, setUser] = useState();
const [accessToken, setAccessToken] = useState();
const [session, setSession] = useState();
const [loading, setLoading] = useState(true);
useEffect(() => {
// Check active sessions and sets the user and session
const session = altogic.auth.getSession();
const user = altogic.auth.getUser();
setUser(user ?? null);
setSession(session ?? null);
setLoading(false);
}, []);
const value = {
user,
session,
setUser,
setSession,
loading,
setLoading,
accessToken,
setAccessToken,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
Creating Reset Password page
Let's create ResetPassword.js
inside the components/
folder and open ResetPassword.js
and copy the below code block to call the resetPwdWithToken
method with access_token.
import { useRef, useState } from "react";
import { useAuth } from "../contexts/Auth";
import { altogic } from "../helpers/altogic";
import { useNavigate } from "react-router-dom";
export function ResetPassword() {
// Get current user and signOut function from context
const { user, accessToken } = useAuth();
const [errors, setError] = useState(null);
const navigate = useNavigate();
const passwordRef = useRef();
async function handleChangePassword() {
let response = await altogic.auth.resetPwdWithToken(
accessToken,
passwordRef.current.value
);
console.log(response);
// Signout and redirect the user to Login page
const { errors } = await altogic.auth.signOutAll();
if (errors) return setError(errors);
}
return (
<>
<div style={{ margin: "20px 20px" }}>
{/* Displays the user ID */}
<p>Welcome, {user?.email} !</p>
<h2> Reset Password</h2>
{/* Input to collect new password */}
<div>
<label>New Password:</label>
<input type="password" name="password" ref={passwordRef} />
<input
type="button"
value="Reset password"
onClick={handleChangePassword}
/>
</div>
<pre>{user && JSON.stringify(user, null, 3)}</pre>
<pre>{errors && JSON.stringify(errors, null, 3)}</pre>
</div>
</>
);
}

Let's open App.js
to add reset-password
route, so copy the following code block.
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Home } from "./components/Home";
import { Signup } from "./components/Signup";
import { Verification } from "./components/Verification";
import { Redirect } from "./components/Redirect";
import { Login } from "./components/Login";
import { PrivateRoute } from "./components/PrivateRoute";
import { AuthProvider } from "./contexts/Auth";
import { Profile } from "./components/Profile";
import { ResetPassword } from "./components/ResetPassword";
export default function App() {
return (
<div>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route
path="/"
element={
<PrivateRoute>
<Home />
</PrivateRoute>
}
/>
<Route
path="/profile"
element={
<PrivateRoute>
<Profile />
</PrivateRoute>
}
/>
<Route
path="/reset-password"
element={
<PrivateRoute>
<ResetPassword />
</PrivateRoute>
}
/>
<Route path="/signup" element={<Signup />} />
<Route path="/auth-redirect" element={<Redirect />} />
<Route path="/verification" element={<Verification />} />
<Route path="/login" element={<Login />} />
</Routes>
</AuthProvider>
</BrowserRouter>
</div>
);
}
Updating Redirect Page
We need to use query string parameters such as reset-pwd
and change-email
to handle the actions on Redirect
page.
So, Let's open the Redirect.js
and copy the following code.
import React, { useEffect, useState } from "react";
import { altogic } from "../helpers/altogic";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useAuth } from "../contexts/Auth";
export function Redirect() {
const navigate = useNavigate();
const { session, setSession, setUser, setAccessToken } = useAuth();
const [errors, setError] = useState(null);
const [searchParams] = useSearchParams();
let queryParam = searchParams.get("action");
useEffect(() => {
async function fetchData() {
if (queryParam === "change-email") {
alert("Email changed successfully!");
let { user } = await altogic.auth.getUserFromDB();
setUser(user);
navigate("/");
} else if (queryParam === "reset-pwd") {
let accessToken = searchParams.get("access_token");
setAccessToken(accessToken ?? null);
navigate("/reset-password");
} else {
let { session, user, errors } = await altogic.auth.getAuthGrant();
setSession(session);
setUser(user);
// If error occurs, set error state
if (errors) return setError(errors);
navigate("/");
}
}
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return !session ? (
<div style={{ margin: "20px 20px", display: "flex", alignItems: "center" }}>
You are redirecting...
</div>
) : (
<div style={{ margin: "20px 20px" }}>
Please wait ...
<pre>{errors && JSON.stringify(errors, null, 3)}</pre>
</div>
);
}
Conclusion
We have completed our starter authentication application. We define different routes and functionalities to cover all the needs of the authentication flow. We have implement
- Login
- Signup
- Home
- Profile
- Verification
- Redirect
- Reset Password
pages for authentication starter app and implement Signout, Change Password, Change Email, Reset Password functionalities.