Building a Simple React App with Basic Authentication

Welcome to this beginner’s guide to creating a React app using Vite! This tutorial includes a navigation bar, login link, dashboard, and admin section, integrating Basic Authentication with a Node.js Express server at localhost:3000. The dashboard is for all logged-in users, while the admin section is for “admin” users only. We’ll use plain JavaScript and CSS for simplicity.

What You Need

Set Up the React Project with Vite

Run this command to create a new Vite React app:

npm create vite@latest

Move into the project folder:

cd react-vite-auth

Install the dependencies:

npm install

Start the development server:

npm run dev

Open http://localhost:5173 in your browser to see the default app.

Add React Router

Install React Router for navigation:

npm install react-router-dom

Configure Routing

Replace src/App.jsx with this code:

import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Navbar from './Navbar.jsx';
import Dashboard from './Dashboard.jsx';
import Home from './Home.jsx'; 
import Admin from './Admin.jsx'; 
import Login from './Login.jsx'; 

const App = () => {
  return (
    <Router>
      <Navbar />
      <div className="content">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/admin" element={<Admin />} />
          <Route path="/login" element={<Login />} />
        </Routes>
      </div>
    </Router>
  );
};

export default App;

Create src/App.css for styling:

.content {
  max-width: 1200px;
  margin: 0 auto;
}

Update src/index.css for global styling:

:root {
  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
  color: #213547;
  background-color: #ffffff;
}

body {
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
}

a {
  color: #646cff;
  text-decoration: none;
}

h1 {
  font-size: 2em;
}

button {
  border-radius: 4px;
  border: 1px solid #ccc;
  padding: 0.5em 1em;
  font-size: 1em;
  font-family: inherit;
  background-color: #f9f9f9;
  cursor: pointer;
}

Create Navigation Bar

Create src/Navbar.jsx:

import React from 'react';
import { Link} from 'react-router-dom';

import './Navbar.css';

const Navbar = () => {


  return (
    <nav className="navbar">
      <div className="container">
        <div className="nav-links nav-links-left">
          <Link to="/" className="nav-link">Home</Link>
         
        </div>
        <div className="nav-links nav-links-right">
          <Link to="/dashboard" className="nav-link">Dashboard</Link>
          <Link to="/admin" className="nav-link">Admin</Link>
          <Link to="/login" className="nav-link">Login</Link>
        </div>
      </div>
    </nav>
  );
};

export default Navbar;

Create src/Navbar.jsx for styling:

.navbar {
  background-color: #333;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  position: relative;
}

.nav-links {
  display: flex;
}

.nav-links-left {
  flex: 1;
  display: flex;
  justify-content: flex-start;
}

.nav-links-right {
  flex: 1;
  display: flex;
  justify-content: flex-end;
}

.nav-link {
  color: white;
  text-decoration: none;
  padding: 0.5rem 1rem;
}

.nav-link:hover {
  color: #ddd;
}

.logout {
  background: none;
  border: none;
  cursor: pointer;
}

Create Pages

Add the following files:

Home.jsx:

import React from 'react';

const Home = () => {
  return <h1 className="title">Welcome to the Home Page</h1>;
};

export default Home;

Login.jsx:

import React from 'react';

const Login = () => {
  return (
       <h1>Please provide your credentials</h1>
  );
};

export default Login;
  

Dashboard.jsx:

import React from 'react';

const Dashboard = () => {
  return (
       <h1>Welcome to Dashboard</h1>
  );
};

export default Dashboard;

Admin.jsx:

import React from 'react';

const Admin = () => {
  return (
       <h1>Admin section</h1>
  );
};

export default Admin;

Run and Test the App

Start the React app and Node.js server:

  • Run npm run dev in react-vite-auth.
    Visit http://localhost:5173:
  • Test the navigation bar and all the pages

Adding Authentication Logic

Create useAuth.js:

import { useState, useEffect } from 'react';

const useAuth = () => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [userRole, setUserRole] = useState(null);

  useEffect(() => {
    const token = localStorage.getItem('authToken');
    if (token) {
      setIsAuthenticated(true);
      const role = localStorage.getItem('userRole') || 'user';
      setUserRole(role);
    }
  }, []);

  const login = (username, password) => {
    const credentials = btoa(`${username}:${password}`);
    fetch('http://localhost:3000/user', {
      headers: { 'Authorization': `Basic ${credentials}` },
    })
      .then(response => {
        if (response.ok){ 
            console.log('Login successful');
            return response.json();
        }
        else if (response.status === 401) throw new Error('Invalid credentials');
      })
      .then(data => {
        setIsAuthenticated(true);
        setUserRole(data.role);
        localStorage.setItem('authToken', credentials);
        localStorage.setItem('userRole', data.role);
      })
      .catch(error => console.error('Login failed:', error));
  };

  const logout = () => {
    setIsAuthenticated(false);
    setUserRole(null);
    localStorage.removeItem('authToken');
    localStorage.removeItem('userRole');
  };

  return { isAuthenticated, userRole, login, logout };
};

export default useAuth;

Add Proper Login Page

Update Login.jsx:

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import useAuth from './useAuth';
import './Login.css';

const Login = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const { login } = useAuth();
  const navigate = useNavigate();

  const handleSubmit = (e) => {
    e.preventDefault();
    login(username, password);
    setTimeout(() => {
        navigate('/dashboard');
      }, 500); // Wait 0.5s before navigating.
  };

  return (
    <div className="login-container">
      <h1 className="title">Login</h1>
      <form onSubmit={handleSubmit} className="login-form">
        <input
          type="text"
          value={username}
          onChange={(e) => setUsername(e.target.value)}
          placeholder="Username"
          className="input"
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Password"
          className="input"
        />
        <button type="submit" className="button">Login</button>
      </form>
    </div>
  );
};

export default Login;

Create Login.css:

.login-container {
  padding: 2rem;
  max-width: 400px;
  margin: 0 auto;
}

.title {
  font-size: 1.5rem;
  margin-bottom: 1rem;
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.input {
  padding: 0.5rem;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.button {
  padding: 0.5rem;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.button:hover {
  background-color: #0056b3;
}

Update Pages to Consider Authentication and Role Status

Update Dashboard.jsx:

import React from 'react';
import useAuth from './useAuth';

const Dashboard = () => {
  const { isAuthenticated, userRole } = useAuth();

  if (!isAuthenticated) {
    return <p className="message">Please log in to view the dashboard.</p>;
  }

  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {userRole}! This is your dashboard.</p>
    </div>
  );
};

export default Dashboard;

Update Admin.jsx:

import React from 'react';
import useAuth from './useAuth';

const Admin = () => {
  const { isAuthenticated, userRole } = useAuth();

  if (!isAuthenticated) {
    return <p className="message">Please log in to view the admin section.</p>;
  }
  if (userRole !== 'admin') {
    return <p className="message">Access denied. Admins only.</p>;
  }

  return (
    <div >
      <h1>Admin Section</h1>
      <p>Welcome, Admin! Manage your settings here.</p>
    </div>
  );
};

export default Admin;

Implement Logout and Role-sensitive Navbar

Update Navbar.jsx:

import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
import useAuth from './useAuth';

import './Navbar.css';

const Navbar = () => {
  const { isAuthenticated, userRole, logout } = useAuth();
  const navigate = useNavigate();

  const handleLogout = () => {
    logout();
    navigate('/');
  };

  return (
    <nav className="navbar">
      <div className="container">
        <div className="nav-links nav-links-left">
          <Link to="/" className="nav-link">Home</Link>      
        </div>
        <div className="nav-links nav-links-right">
        {isAuthenticated ? (
          <>
            <Link to="/dashboard" className="nav-link">Dashboard</Link>
             {userRole === 'admin' && (
                <Link to="/admin" className="nav-link">Admin</Link>
             )}
             <button onClick={handleLogout} className="nav-link logout">
                Logout
             </button>

          </>
        ) : (
            <Link to="/login" className="nav-link">Login</Link>
        )}
              
        </div>
      </div>
    </nav>
  );
};

export default Navbar;

Run and Test the App

Start the React app and Node.js server:

  • Node.js server: Run npm run dev in its directory.
  • React app: Run npm run dev in react-vite-auth. Visit http://localhost:5173:
  • Click “Login,” enter admin/password123 or user/user123, and submit.
  • Navigate to “Dashboard” (for all logged-in users) and “Admin” (for admin only).

Fixing Common Problems

  • Login Fails: Check if the Node.js server is running at localhost:3000 with userlist.json. Look at browser console errors (F12 > Console).
  • Routing Issues: Ensure react-router-dom is installed. Try incognito mode or clear cache.
  • Admin Access Denied: Verify userRole is set in useAuth after login.
  • CORS Issues: Confirm the Node.js server allows http://localhost:5173.

Wrap Up

You’ve built a React app with Vite using plain JavaScript and CSS, featuring navigation, Basic Authentication, a dashboard, and an admin section! Improve it with token-based auth or more features. Check out Vite documentation and React docs for more.

Happy coding!

Leave a Reply