Lesson 53 of 60 – React Authentication
88%

React Authentication

Authentication is the process of verifying who a user is. In a React application, authentication is commonly connected to a backend API that handles login, user accounts, sessions, and authentication tokens.

Note: React usually handles the user interface for authentication, while the backend should verify credentials and enforce access rules.

1. What is Authentication?

Authentication verifies the identity of a user.

For example, a login form may ask for:

  • Email address
  • Username
  • Password

The backend verifies the submitted credentials.

2. Authentication vs Authorization

Authentication Authorization
Checks who the user is Checks what the user is allowed to access
Usually happens during login Usually happens after identity is established
Example: Login Example: Accessing an admin page

3. Basic Authentication Flow

User
 ↓
Login Form
 ↓
React
 ↓
Backend API
 ↓
Verify Credentials
 ↓
Authentication Result
 ↓
React Application

4. Login Form

A React login form can collect the user's credentials.

function Login() {

    const [email, setEmail] =
        useState("");

    const [password, setPassword] =
        useState("");

    return (
        <form>

            <input
                type="email"
                value={email}
                onChange={e =>
                    setEmail(
                        e.target.value
                    )
                }
            />

            <input
                type="password"
                value={password}
                onChange={e =>
                    setPassword(
                        e.target.value
                    )
                }
            />

        </form>
    );
}

5. Submitting Login Data

The login form can send credentials to a backend API.

async function handleLogin(e) {

    e.preventDefault();

    const response = await fetch(
        "/api/login",
        {
            method: "POST",
            headers: {
                "Content-Type":
                    "application/json"
            },
            body: JSON.stringify({
                email,
                password
            })
        }
    );
}

6. Login Response

A backend may return information indicating whether authentication succeeded.

{
    "user": {
        "id": 101,
        "name": "Rahul"
    },
    "token": "example-token"
}

The exact response structure depends on the backend API.

7. Authentication State

React can maintain information about the current authentication state.

const [user, setUser] =
    useState(null);

A value of null can represent that no authenticated user is currently available in the application's state.

8. Setting the Authenticated User

After successful authentication, the application can update its user state.

setUser(responseData.user);

Components can then use this state to display user-specific information.

9. Login Success

After a successful login, the application may navigate the user to another page.

if (response.ok) {

    setUser(data.user);

    navigate("/dashboard");
}

The exact navigation behavior depends on the application's routing design.

10. Login Error

The application should provide feedback when authentication fails.

if (!response.ok) {

    setError(
        "Invalid email or password"
    );

}

The backend should decide whether the submitted credentials are valid.

11. Loading During Login

Login is asynchronous, so a loading state can prevent repeated submissions while the request is in progress.

const [loading, setLoading] =
    useState(false);

Before sending the request:

setLoading(true);

12. Complete Login Request

async function handleLogin(e) {

    e.preventDefault();

    setLoading(true);
    setError("");

    try {

        const response = await fetch(
            "/api/login",
            {
                method: "POST",
                headers: {
                    "Content-Type":
                        "application/json"
                },
                body: JSON.stringify({
                    email,
                    password
                })
            }
        );

        if (!response.ok) {
            throw new Error(
                "Login failed"
            );
        }

        const data =
            await response.json();

        setUser(data.user);

    } catch (error) {

        setError(error.message);

    } finally {

        setLoading(false);

    }
}

13. Authentication Token

Some authentication systems return a token after successful login.

{
    "token": "example-token"
}

The client can use an authentication token when making later API requests, according to the backend's authentication design.

14. Sending a Bearer Token

A common HTTP authentication pattern is the Bearer authentication scheme.

fetch("/api/profile", {
    headers: {
        Authorization:
            `Bearer ${token}`
    }
});

The backend should validate the token before returning protected data.

15. Storing Authentication Information

Applications need a strategy for maintaining authentication between requests. The strategy depends on the backend and security design.

Some applications use:

  • Secure cookies
  • Server-managed sessions
  • Access tokens
  • Refresh tokens
Important: Do not automatically store sensitive authentication credentials in browser storage just because it is convenient. Choose a storage approach based on the security requirements of the application.

16. Authentication Context

React Context can be used to make authentication state available to many components.

const AuthContext =
    createContext(null);

An AuthProvider can then share the current user and authentication functions.

17. AuthProvider

function AuthProvider({
    children
}) {

    const [user, setUser] =
        useState(null);

    return (
        <AuthContext.Provider
            value={{
                user,
                setUser
            }}
        >

            {children}

        </AuthContext.Provider>
    );
}

18. Reading Authentication Context

function Profile() {

    const {
        user
    } = useContext(
        AuthContext
    );

    return (
        <h2>
            Welcome {user.name}
        </h2>
    );
}

19. Logout

Logout removes or invalidates the application's authenticated state according to the authentication system.

function logout() {

    setUser(null);

    navigate("/login");
}

For server-managed sessions or token-based systems, logout may also require a backend request or other server-side action.

20. Logout API Request

Some authentication systems provide a logout endpoint.

async function logout() {

    await fetch(
        "/api/logout",
        {
            method: "POST"
        }
    );

    setUser(null);

    navigate("/login");
}

21. Checking Authentication Status

When an application starts, it may need to determine whether the current user has an active authenticated session.

useEffect(() => {

    fetch("/api/me")
        .then(response => {

            if (response.ok) {
                return response.json();
            }

            throw new Error(
                "Not authenticated"
            );
        })
        .then(data => {
            setUser(data);
        })
        .catch(() => {
            setUser(null);
        });

}, []);

22. Authentication Loading State

When checking the current session, it can be useful to distinguish between "not authenticated" and "authentication status is still being checked."

const [authLoading, setAuthLoading] =
    useState(true);

After the authentication check completes:

setAuthLoading(false);

23. Authentication Flow

Open Application
       ↓
Check Authentication
       ↓
Authenticated?
   ↙          ↘
 Yes           No
 ↓             ↓
Dashboard     Login
 ↓
Protected Data
       ↓
Logout
       ↓
Login

24. Authentication and React Router

Authentication state can work together with React Router to control which pages are available in the user interface.

<Routes>

    <Route
        path="/login"
        element={<Login />}
    />

    <Route
        path="/dashboard"
        element={<Dashboard />}
    />

</Routes>

Access control should ultimately be enforced by the backend, not only by hiding frontend routes.

25. Authentication State Structure

An authentication context may contain more than just the current user.

const authValue = {
    user,
    loading,
    login,
    logout
};

This provides a central interface for authentication-related operations.

26. Common Authentication Mistakes

  • Trusting frontend authentication checks as the only security mechanism.
  • Storing sensitive credentials insecurely.
  • Not validating credentials on the backend.
  • Ignoring API errors during login.
  • Not handling loading states.
  • Forgetting to clear authentication state during logout.
  • Exposing sensitive information in frontend code.
  • Assuming that hiding a route protects backend data.
  • Not checking whether an authentication session has expired.

27. Authentication Architecture

React
  ↓
Login Form
  ↓
Authentication API
  ↓
Backend
  ↓
Database / Session System
  ↓
Authentication Result
  ↓
React Auth State
  ↓
Application UI

28. Complete Auth Context Example

import {
    createContext,
    useContext,
    useState
} from "react";

const AuthContext =
    createContext(null);

function AuthProvider({
    children
}) {

    const [user, setUser] =
        useState(null);

    async function login(
        email,
        password
    ) {

        const response = await fetch(
            "/api/login",
            {
                method: "POST",

                headers: {
                    "Content-Type":
                        "application/json"
                },

                body: JSON.stringify({
                    email,
                    password
                })
            }
        );

        if (!response.ok) {
            throw new Error(
                "Login failed"
            );
        }

        const data =
            await response.json();

        setUser(data.user);
    }

    function logout() {

        setUser(null);
    }

    return (
        <AuthContext.Provider
            value={{
                user,
                login,
                logout
            }}
        >

            {children}

        </AuthContext.Provider>
    );
}

function Profile() {

    const {
        user,
        logout
    } = useContext(
        AuthContext
    );

    if (!user) {
        return (
            <p>
                Please log in.
            </p>
        );
    }

    return (
        <div>

            <h2>
                Welcome {user.name}
            </h2>

            <button
                onClick={logout}
            >

                Logout

            </button>

        </div>
    );
}

export default AuthProvider;

29. Complete Login Example

import {
    useState,
    useContext
} from "react";

import {
    useNavigate
} from "react-router-dom";

function Login() {

    const {
        login
    } = useContext(
        AuthContext
    );

    const navigate =
        useNavigate();

    const [email, setEmail] =
        useState("");

    const [password, setPassword] =
        useState("");

    const [error, setError] =
        useState("");

    const [loading, setLoading] =
        useState(false);

    async function handleSubmit(e) {

        e.preventDefault();

        setLoading(true);
        setError("");

        try {

            await login(
                email,
                password
            );

            navigate("/dashboard");

        } catch (err) {

            setError(
                err.message
            );

        } finally {

            setLoading(false);

        }
    }

    return (
        <form
            onSubmit={handleSubmit}
        >

            <input
                type="email"
                placeholder="Email"
                value={email}
                onChange={e =>
                    setEmail(
                        e.target.value
                    )
                }
            />

            <input
                type="password"
                placeholder="Password"
                value={password}
                onChange={e =>
                    setPassword(
                        e.target.value
                    )
                }
            />

            {error && (
                <p>
                    {error}
                </p>
            )}

            <button
                type="submit"
                disabled={loading}
            >

                {loading
                    ? "Logging in..."
                    : "Login"}

            </button>

        </form>
    );
}

export default Login;

30. Authentication Best Practices

  • Always verify credentials on the backend.
  • Use HTTPS for authentication-related communication.
  • Do not put passwords directly into frontend code.
  • Do not assume frontend route protection is sufficient security.
  • Handle login errors clearly.
  • Show an appropriate loading state during authentication requests.
  • Manage authentication state in a consistent way.
  • Handle logout correctly according to the backend authentication system.
  • Protect sensitive API endpoints on the server.
  • Choose token or session storage based on the security design of the application.
Login
  ↓
Backend Verification
  ↓
Authenticated User
  ↓
Auth State
  ↓
Application
  ↓
Logout

📌 Key Points

  • Authentication verifies a user's identity.
  • Authorization determines what an authenticated user can access.
  • React can provide the login and authentication user interface.
  • The backend should verify credentials and enforce access rules.
  • useState can store authentication state in a component.
  • Context can share authentication state across components.
  • Authentication APIs commonly provide login and logout operations.
  • Loading and error states are important during authentication requests.
  • Frontend route checks should not be treated as the only security mechanism.
  • Authentication storage should be selected carefully according to security requirements.

🧠 Quick Quiz

Question: What is the primary purpose of authentication?