Introduction
In the previous tutorial, we prepared initial files and completed the Login, Signup, Redirect, Verification, and Home pages. Now we will prepare our backend and connect with our React application.
So, let’s start!
Creating an Altogic App
We will use Altogic as a backend service platform, so let’s visit Altogic Designer and create an account.
After creating an account, you will see the workspace where you can access your apps.

Click + New app
and follow the instructions;
- In the App name field, enter a name for the app.
- Enter your subdomain.
- Select your execution environment region.
- And select your free execution environment pricing plan.

Then click Next
and select Basic Authentication
template. This template is based on session authentication and highly recommended to secure your apps.

Then click Next
to confirm and create an app. Also, here we can see some of the details the about the application. Let’s click Create
to finish the application creation process.

Awesome! We have created our application; now click/tap on the newly created app to launch the Designer.
info
This is the only configuration we need to do in Altogic Designer. Still to access the app and use the Altogic client library, we should get envUrl
and clientKey
of this app.
Click the Home icon at the left sidebar to copy the envUrl
and clientKey
.

Return back to VSCode to wire backend and frontend
Our backend is now ready and running on the server. ✨
Now, we can install the Altogic client library to our React app to connect our frontend with the backend.
# using npm
npm install altogic
# OR is using yarn
yarn add altogic
Let’s create a helpers/
folder inside of the src/
directory to add altogic.js
file.

Open altogic.js
and paste below code block to export the altogic
client instance.
import { createClient } from "altogic";
// This `envUrl` and `clientKey` is sample you need to create your own.
let envUrl = "https://auth.c1-na.altogic.com";
let clientKey = "e574fee1fb2b443...a8598ca68b7d8";
const altogic = createClient(envUrl, clientKey);
export { altogic };
note
Replace envUrl and clientKey which is shown in the Home view of Altogic Designer.
Previously we have created our form components in the Signup and Login components.
Let’s open the Signup.js
to collect the form values to submit the form. So, please copy the below code and paste it to the regarding file.
import { useRef, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { altogic } from "../helpers/altogic";
export function Signup() {
const emailRef = useRef();
const passwordRef = useRef();
const [errors, setError] = useState(null);
const navigate = useNavigate();
async function handleSubmit(e) {
e.preventDefault();
// Get email and password input values
const email = emailRef.current.value;
const password = passwordRef.current.value;
// Calls `signUpWithEmail` function from the Altogic client library
const { errors, user } = await altogic.auth.signUpWithEmail(
email,
password
);
// If error occurs, set error state
if (errors) return setError(errors);
// If user.emailVerified is false, redirect to verification page else redirect to home page
if (user.emailVerified === false) {
console.log("Email verification status:", user.emailVerified);
navigate("/verification");
} else {
navigate("/");
}
}
return (
// Create signup form with email, password, and submit button
<div style={{ margin: "20px 20px" }}>
<h1>Signup</h1>
<form onSubmit={handleSubmit}>
<label>Email:</label>
<input type="text" name="email" ref={emailRef} />
<label>Password:</label>
<input type="password" name="password" ref={passwordRef} />
<input type="submit" value="Signup" />
</form>
<p style={{ margin: "20px 0px" }}>
Already have an account? <Link to="/login">Login</Link>
</p>
{/* Display errors if any occurs */}
<pre>{errors && JSON.stringify(errors, null, 3)}</pre>
</div>
);
}
info
We are using useRef hook to collect email and password values and adding handleSubmit function to the button to send a request with altogic.auth.signupWithEmail
method to create a user with a given email and password value.
Here is the crucial part when the email/password combination is valid, the application redirect users to the Verification page. If this combination is not valid, it shows errors on the page within the added <pre>
tags.
Okay, Let’s test it and run the application with npm run start
and visit the https://localhost:3000/signup



note
Here we can see that Altogic automatically checks the validation of your data to secure your apps. Also you can add custom field validation rules to your models and fields.
As seen above, if the form is submitted successfully, Altogic sends a verification email to the user like below. Once the user clicks the link in the email, it navigates user to Redirect page, which we will implement later.

Create an authentication context
We need to share data across our components. We can use this hook throughout our application by creating an authentication context. Passing down the authentication status to each component is redundant. It leads to prop drilling, so using context is a good option. If you are not familiar with Context API in React, check out their docs here.
tip
The React Context API is a state management tool used for sharing data across React components.
Let’s create contexts/
folder inside of the src/
directory to add Auth.js
file inside it.

Open Auth.js
and copy following code.
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 [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);
}, []);
// Will be passed down to Signup, Login, and Home components
const value = {
user,
session,
setUser,
setSession,
loading,
setLoading,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
Using the Authentication hook
In order to use the useAuth
hook, we need to wrap our application with the AuthProvider
in the App.js
.
Open the App.js
and copy following code.
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 { AuthProvider } from "./contexts/Auth";
export default function App() {
return (
<div>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/" element={<Home />} />
<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>
);
}
We can now import useAuth
hook anywhere in our application with importing and calling the functional component.
note
We added Signup and Verification pages, and if the user clicks the link in the email, Altogic redirects the user to a specific route.
Let’s visit Altogic Designer to set or get that specific route URL to bound with our Redirect page.
Here! We can access the Authentication Settings of our app inside of the Settings view, as seen above. And we can get/set https://localhost:3000/auth-redirect
value from the Redirect url section.
Now, we can update the Redirect.js
component route and match it with the React app to know the given access token is correct to generate the session.
tip
We created the App.js and inserted the value correctly previously; if you changed it, you could update it according to your configuration.

To implement the Redirect page, let’s open Redirect.js
and paste below code block.
import React, { useEffect, useState } from "react";
import { altogic } from "../helpers/altogic";
import { useNavigate } from "react-router-dom";
import { useAuth } from "../contexts/Auth";
export function Redirect() {
const navigate = useNavigate();
const { session, setSession, setUser } = useAuth();
const [errors, setError] = useState(null);
useEffect(() => {
async function fetchData() {
let { session, user, errors } = await altogic.auth.getAuthGrant();
setSession(session);
setUser(user);
// If error occurs, set error state
if (errors) return setError(errors);
navigate("/");
console.log("session", session);
}
fetchData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return !session ? (
<div style={{ margin: "20px 20px" }}>
You are redirecting to the profile page...
</div>
) : (
<div style={{ margin: "20px 20px" }}>
Not verified...
<pre>{errors && JSON.stringify(errors, null, 3)}</pre>
</div>
);
}
In the code above, We implement useEffect hook to fetch the data from the backend once the page is rendered, with the altogic.auth.getAuthGrant method, we are fetching authentication grants in Redirect.js
.
This method gets the accessToken from the query string parameter. It sets session and user information to localStorage to use in further queries.
Creating Login page
Let’s create the login page to test the app and complete the form submission parts to test the general functionality.
import { useRef, useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { useAuth } from "../contexts/Auth";
import { altogic } from "../helpers/altogic";
export function Login() {
const emailRef = useRef();
const passwordRef = useRef();
const { setUser } = useAuth();
const { setSession } = useAuth();
const [errors, setError] = useState(null);
const navigate = useNavigate();
async function handleSubmit(e) {
e.preventDefault();
// Get email and password input values
const email = emailRef.current.value;
const password = passwordRef.current.value;
// Call Altogic client library `signInWithEmail` function.
const { errors, user, session } = await altogic.auth.signInWithEmail(
email,
password
);
setUser(user ?? null);
setSession(session ?? null);
if (errors) return setError(errors);
if (user && session) {
navigate("/");
}
}
return (
// Create login form with email, password, and submit button
<div style={{ margin: "20px 20px" }}>
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<pre>{errors && JSON.stringify(errors, null, 3)}</pre>
<label>Email:</label>
<input type="text" name="email" ref={emailRef} />
<label>Password:</label>
<input type="password" name="password" ref={passwordRef} />
<input type="submit" value="Signup" />
</form>
<p>
{" "}
Don't you have an account? <Link to="/signup">Signup</Link>
</p>
</div>
);
}
Again, using useRef to get the form’s value and adding handleSubmit async function to send a request with altogic.auth.signInWithEmail method. Here we use previously created authentication context to set user and session information, route users, and display error messages etc.,
Creating Private Routes
To secure the application and authorize users to access specified routes let’s create PrivateRoute.js
inside the components directory and paste the code below.
import React from "react";
import { useLocation, Navigate } from "react-router-dom";
import { useAuth } from "../contexts/Auth";
export function PrivateRoute({ children }) {
const { session } = useAuth();
let location = useLocation();
return session ? (
children
) : (
<Navigate to="/login" state={{ from: location }} replace />
);
}
note
Previously we have created our authentication context to use user and session information. And, here, we are controlling session to route users, whether the Login
page or the children.
Now we can wrap necessary routes with the PrivateRoute component to specify access in the App.js
. Let’s open it and wrap our Home
page with the PrivateRoute
as the screen below.

Here also you can copy the code;
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";
export default function App() {
return (
<div>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route
path="/"
element={
<PrivateRoute>
<Home />
</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>
);
}
Let’s continue with the Home page to complete our pages. Open Home.js and paste the below code.
import { useNavigate } from "react-router";
import { useAuth } from "../contexts/Auth";
import { altogic } from "../helpers/altogic";
export function Home() {
// Get current user and signOut function from context
const { user, setUser, setSession } = useAuth();
const navigate = useNavigate();
async function handleSignOut() {
// Ends user session
await altogic.auth.signOut();
setUser(null);
setSession(null);
// Redirects the user to Login page
navigate("/login");
}
return (
<>
<div style={{ margin: "20px 20px" }}>
{/* Displays the user ID */}
<p>Welcome, {user?._id} !</p>
<span>
<p>
Your email verification status:{" "}
{user?.emailVerified ? "Verified" : "Not Verified"}
</p>
</span>
<pre>{user && JSON.stringify(user, null, 3)}</pre>
<button style={{ margin: "20px 20px" }} onClick={handleSignOut}>
Sign out
</button>
</div>
</>
);
}
Congratulations!✨
You had completed the most critical part of the Authentication flow, which includes private routes, sign-up, sign-in, and sign-out operations.
These are the baselines of your applications. If you want to learn how to handle changing passwords, changing emails, and resetting password flows, continue to part 3.
BONUS: Why users are redirected to login page after successfully verified?
Solution: The problem based on this issue https://github.com/facebook/react/issues/24502
- In that tutorial Let’s solve it by removing the
<React.StrictMode>
tags. Later we will provide better solution, and this problem only occurs on development environment.
Open index.js
and replace below code.
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();