Skip to content

AnilaAnilaN/auth_system

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔐 Full-Stack Authentication System

A complete authentication system built with React, Node.js, Express, and MySQL. Features user registration, login, JWT authentication, and a modern, responsive UI with custom CSS.

App Screenshot


📋 Table of Contents


✨ Features

Authentication

  • ✅ User registration with email validation
  • ✅ Secure password hashing with bcrypt
  • ✅ JWT token-based authentication
  • ✅ Password visibility toggle
  • ✅ Form validation (client & server-side)
  • ✅ Protected routes with middleware

UI/UX

  • ✅ Modern, clean design with custom CSS
  • ✅ Fully responsive (mobile, tablet, desktop)
  • ✅ Smooth animations and transitions
  • ✅ Real-time error/success messages
  • ✅ Loading states for better UX
  • ✅ Keyboard navigation support

Security

  • ✅ Password encryption (bcrypt)
  • ✅ JWT token authentication
  • ✅ SQL injection prevention
  • ✅ CORS configuration
  • ✅ Input validation & sanitization
  • ✅ Secure session management

🛠️ Tech Stack

Frontend

  • React (v18+) - UI Library
  • Lucide React - Icon library
  • Custom CSS - Styling (no framework dependencies)

Backend

  • Node.js - Runtime environment
  • Express.js - Web framework
  • MySQL2 - Database driver
  • bcryptjs - Password hashing
  • jsonwebtoken - JWT authentication
  • dotenv - Environment variables
  • cors - Cross-origin resource sharing

Database

  • MySQL (via MySQL Workbench or XAMPP)

📁 Project Structure

project-root/
│
├── auth-backend/                 # Backend API
│   ├── config/
│   │   └── database.js          # Database connection
│   ├── controllers/
│   │   └── authController.js    # Authentication logic
│   ├── middleware/
│   │   └── authMiddleware.js    # JWT verification
│   ├── routes/
│   │   └── authRoutes.js        # API routes
│   ├── .env                     # Environment variables
│   ├── server.js                # Entry point
│   └── package.json
│
├── auth-frontend/               # React frontend
│   ├── public/
│   │   └── index.html
│   ├── src/
│   │   ├── pages/
│   │   │   ├── Login.jsx        # Login component
│   │   │   └── Register.jsx     # Register component
│   │   ├── styles/
│   │   │   └── auth.css         # Authentication styles
│   │   ├── api/
│   │   │   └── auth.js          # API helper (optional)
│   │   ├── App.js               # Main component
│   │   ├── App.css              # App styles
│   │   ├── index.js             # Entry point
│   │   └── index.css            # Global styles
│   └── package.json
│
├── screenshot.png               # Application screenshot
└── README.md                    # This file

📦 Prerequisites

Before you begin, ensure you have the following installed:

Check Installations

node --version    # Should be v14 or higher
npm --version     # Should be 6 or higher
mysql --version   # Should be 5.7 or higher

🚀 Installation

1. Database Setup (MySQL)

Step 1.1: Start MySQL Server

Using XAMPP:

  1. Open XAMPP Control Panel
  2. Start Apache and MySQL modules
  3. MySQL will run on port 3306 by default

Using Standalone MySQL:

  • MySQL should be running as a service automatically

Step 1.2: Create Database using MySQL Workbench

  1. Open MySQL Workbench
  2. Connect to your local MySQL server (localhost:3306)
  3. Enter password if prompted (XAMPP default is empty or root)
  4. Click Query tab or press Ctrl+T
  5. Copy and paste the following SQL:
-- Create the database
CREATE DATABASE IF NOT EXISTS auth_system;

-- Use the database
USE auth_system;

-- Create users table
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Create index on email for faster lookups
CREATE INDEX idx_email ON users(email);
  1. Click the lightning bolt icon ⚡ or press Ctrl+Shift+Enter
  2. Verify success in the Action Output panel

Step 1.3: Verify Database

-- Check if database exists
SHOW DATABASES;

-- Check tables
USE auth_system;
SHOW TABLES;

-- Check table structure
DESCRIBE users;

Expected Output:

+------------+--------------+------+-----+-------------------+
| Field      | Type         | Null | Key | Default           |
+------------+--------------+------+-----+-------------------+
| id         | int          | NO   | PRI | NULL              |
| email      | varchar(255) | NO   | UNI | NULL              |
| password   | varchar(255) | NO   |     | NULL              |
| created_at | timestamp    | YES  |     | CURRENT_TIMESTAMP |
| updated_at | timestamp    | YES  |     | CURRENT_TIMESTAMP |
+------------+--------------+------+-----+-------------------+

2. Backend Setup

Step 2.1: Create Backend Directory

mkdir auth-backend
cd auth-backend
npm init -y

Step 2.2: Install Dependencies

npm install express mysql2 bcryptjs jsonwebtoken dotenv cors body-parser
npm install nodemon --save-dev

Dependencies Installed:

  • express - Web framework
  • mysql2 - MySQL database driver
  • bcryptjs - Password hashing
  • jsonwebtoken - JWT token generation
  • dotenv - Environment variables
  • cors - Cross-origin requests
  • body-parser - Parse request bodies
  • nodemon - Auto-restart server (dev)

Step 2.3: Create Project Files

Create the following directory structure:

mkdir config controllers middleware routes

Create these files in their respective folders:

.env (root of auth-backend):

PORT=5000
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=
DB_NAME=auth_system
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production_12345
JWT_EXPIRE=7d

⚠️ Important: Change JWT_SECRET to a random, secure string in production!

config/database.js:

const mysql = require('mysql2');
require('dotenv').config();

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

const promisePool = pool.promise();

// Test connection
pool.getConnection((err, connection) => {
  if (err) {
    console.error('❌ Database connection failed:', err.message);
  } else {
    console.log('✅ Database connected successfully');
    connection.release();
  }
});

module.exports = promisePool;

controllers/authController.js:

const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const db = require('../config/database');

// Sign Up Controller
exports.signUp = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Validation
    if (!email || !password) {
      return res.status(400).json({ message: 'Email and password are required' });
    }

    if (password.length < 6) {
      return res.status(400).json({ message: 'Password must be at least 6 characters' });
    }

    // Check if user already exists
    const [existingUsers] = await db.execute(
      'SELECT * FROM users WHERE email = ?',
      [email]
    );

    if (existingUsers.length > 0) {
      return res.status(409).json({ message: 'Email already registered' });
    }

    // Hash password
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);

    // Insert user
    const [result] = await db.execute(
      'INSERT INTO users (email, password) VALUES (?, ?)',
      [email, hashedPassword]
    );

    res.status(201).json({
      message: 'Account created successfully! Please sign in.',
      userId: result.insertId
    });

  } catch (error) {
    console.error('SignUp Error:', error);
    res.status(500).json({ message: 'Server error during registration' });
  }
};

// Sign In Controller
exports.signIn = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Validation
    if (!email || !password) {
      return res.status(400).json({ message: 'Email and password are required' });
    }

    // Find user
    const [users] = await db.execute(
      'SELECT * FROM users WHERE email = ?',
      [email]
    );

    if (users.length === 0) {
      return res.status(401).json({ message: 'Invalid email or password' });
    }

    const user = users[0];

    // Check password
    const isPasswordValid = await bcrypt.compare(password, user.password);

    if (!isPasswordValid) {
      return res.status(401).json({ message: 'Invalid email or password' });
    }

    // Generate JWT token
    const token = jwt.sign(
      { id: user.id, email: user.email },
      process.env.JWT_SECRET,
      { expiresIn: process.env.JWT_EXPIRE }
    );

    res.status(200).json({
      message: 'Login successful',
      token,
      user: {
        id: user.id,
        email: user.email,
        createdAt: user.created_at
      }
    });

  } catch (error) {
    console.error('SignIn Error:', error);
    res.status(500).json({ message: 'Server error during login' });
  }
};

// Get User Profile (Protected Route Example)
exports.getProfile = async (req, res) => {
  try {
    const userId = req.user.id;

    const [users] = await db.execute(
      'SELECT id, email, created_at FROM users WHERE id = ?',
      [userId]
    );

    if (users.length === 0) {
      return res.status(404).json({ message: 'User not found' });
    }

    res.status(200).json({ user: users[0] });

  } catch (error) {
    console.error('GetProfile Error:', error);
    res.status(500).json({ message: 'Server error' });
  }
};

middleware/authMiddleware.js:

const jwt = require('jsonwebtoken');

exports.protect = async (req, res, next) => {
  try {
    let token;

    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
      token = req.headers.authorization.split(' ')[1];
    }

    if (!token) {
      return res.status(401).json({ message: 'Not authorized, no token' });
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();

  } catch (error) {
    console.error('Auth Middleware Error:', error);
    res.status(401).json({ message: 'Not authorized, token failed' });
  }
};

routes/authRoutes.js:

const express = require('express');
const router = express.Router();
const authController = require('../controllers/authController');
const { protect } = require('../middleware/authMiddleware');

// Public routes
router.post('/signup', authController.signUp);
router.post('/signin', authController.signIn);

// Protected routes
router.get('/profile', protect, authController.getProfile);

module.exports = router;

server.js:

const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
require('dotenv').config();

const authRoutes = require('./routes/authRoutes');

const app = express();

// Middleware
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// Routes
app.use('/api/auth', authRoutes);

// Health check route
app.get('/api/health', (req, res) => {
  res.json({ status: 'Server is running', timestamp: new Date() });
});

// Error handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ message: 'Something went wrong!' });
});

// 404 handler
app.use((req, res) => {
  res.status(404).json({ message: 'Route not found' });
});

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {
  console.log(`🚀 Server running on port ${PORT}`);
  console.log(`📍 http://localhost:${PORT}`);
});

Step 2.4: Update package.json Scripts

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  }
}

3. Frontend Setup

Step 3.1: Create React App

# Navigate to project root (exit auth-backend folder)
cd ..

# Create React app
npx create-react-app auth-frontend
cd auth-frontend

Step 3.2: Install Dependencies

npm install lucide-react

Step 3.3: Create Directory Structure

# Create folders
mkdir src/pages
mkdir src/styles
mkdir src/api

Step 3.4: Create Component Files

Copy the following files from the artifacts provided earlier:

src/pages/Login.jsx - Login component src/pages/Register.jsx - Register component src/styles/auth.css - Authentication styles src/App.js - Main app component src/App.css - App styles src/index.css - Global styles

src/index.js should be:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

⚙️ Configuration

Backend Configuration (.env)

Variable Description Default
PORT Server port 5000
DB_HOST MySQL host localhost
DB_USER MySQL username root
DB_PASSWORD MySQL password (empty for XAMPP)
DB_NAME Database name auth_system
JWT_SECRET JWT secret key (change in production!)
JWT_EXPIRE Token expiration 7d

Frontend Configuration

Update API endpoint in components if needed:

const API_URL = 'http://localhost:5000/api/auth';

🎮 Running the Application

Step 1: Start MySQL Server

  • XAMPP: Start MySQL in XAMPP Control Panel
  • Standalone: Ensure MySQL service is running

Step 2: Start Backend Server

cd auth-backend
npm run dev

Expected Output:

✅ Database connected successfully
🚀 Server running on port 5000
📍 http://localhost:5000

Step 3: Start Frontend

Open a new terminal window:

cd auth-frontend
npm start

Expected Output:

Compiled successfully!

You can now view auth-frontend in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.x.x:3000

Step 4: Open Application

Navigate to: http://localhost:3000


📡 API Documentation

Base URL

http://localhost:5000/api/auth

Endpoints

1. Sign Up (Register)

POST /api/auth/signup

Request Body:

{
  "email": "user@example.com",
  "password": "password123"
}

Response (Success - 201):

{
  "message": "Account created successfully! Please sign in.",
  "userId": 1
}

Response (Error - 409):

{
  "message": "Email already registered"
}

2. Sign In (Login)

POST /api/auth/signin

Request Body:

{
  "email": "user@example.com",
  "password": "password123"
}

Response (Success - 200):

{
  "message": "Login successful",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 1,
    "email": "user@example.com",
    "createdAt": "2024-01-15T10:30:00.000Z"
  }
}

Response (Error - 401):

{
  "message": "Invalid email or password"
}

3. Get Profile (Protected)

GET /api/auth/profile

Headers:

Authorization: Bearer YOUR_JWT_TOKEN_HERE

Response (Success - 200):

{
  "user": {
    "id": 1,
    "email": "user@example.com",
    "created_at": "2024-01-15T10:30:00.000Z"
  }
}

Response (Error - 401):

{
  "message": "Not authorized, no token"
}

4. Health Check

GET /api/health

Response (200):

{
  "status": "Server is running",
  "timestamp": "2024-01-15T10:30:00.000Z"
}

📸 Screenshots

MySQL Workbench - Database Setup

Database Screenshot


🔒 Security Features

1. Password Security

  • Bcrypt Hashing: Passwords are hashed with salt (10 rounds)
  • Minimum Length: 6 characters required
  • Never Stored Plain: Passwords never stored in plain text

2. JWT Authentication

  • Secure Tokens: JWT tokens for stateless authentication
  • Expiration: Tokens expire after 7 days
  • HTTP-Only: Can be configured for HTTP-only cookies

3. Database Security

  • Prepared Statements: Protection against SQL injection
  • Unique Constraints: Email uniqueness enforced at DB level
  • Indexed Queries: Optimized with email index

4. API Security

  • Input Validation: All inputs validated on server
  • CORS Configuration: Cross-origin requests controlled
  • Error Handling: Generic error messages (no info leakage)
  • Rate Limiting: Can be added with express-rate-limit

5. Frontend Security

  • No localStorage: Tokens stored in sessionStorage
  • XSS Prevention: React's built-in XSS protection
  • HTTPS Ready: Can be deployed with SSL/TLS

🐛 Troubleshooting

Backend Issues

❌ Database Connection Failed

Error: ER_ACCESS_DENIED_ERROR

Solution:

  • Check MySQL is running
  • Verify credentials in .env
  • Test connection in MySQL Workbench

❌ Port Already in Use

Error: listen EADDRINUSE: address already in use :::5000

Solution:

# Find process using port 5000
lsof -i :5000          # Mac/Linux
netstat -ano | findstr :5000   # Windows

# Kill the process or change PORT in .env

❌ Module Not Found

Error: Cannot find module 'express'

Solution:

cd auth-backend
npm install

Frontend Issues

❌ CORS Error

Access to fetch has been blocked by CORS policy

Solution:

  • Ensure backend has app.use(cors()) enabled
  • Check backend is running on correct port

❌ Icons Not Showing

Module not found: Can't resolve 'lucide-react'

Solution:

cd auth-frontend
npm install lucide-react

❌ Connection Error

Connection error. Please try again.

Solution:

  • Verify backend is running (http://localhost:5000)
  • Check API endpoint URLs in components
  • Check browser console for detailed errors

Database Issues

❌ Table Doesn't Exist

Error: Table 'auth_system.users' doesn't exist

Solution:

  1. Open MySQL Workbench
  2. Run the CREATE TABLE SQL script again
  3. Verify with SHOW TABLES;

❌ Duplicate Entry Error

Error: ER_DUP_ENTRY: Duplicate entry for key 'email'

Solution:

  • This email is already registered
  • Use a different email or delete the existing user:
DELETE FROM users WHERE email = 'test@example.com';

🧪 Testing

Manual Testing

Test Registration:

  1. Navigate to http://localhost:3000
  2. Click "Sign Up"
  3. Enter:
    • Email: test@example.com
    • Password: password123
    • Confirm Password: password123
  4. Click "SIGN UP"
  5. Should see: "Account created successfully!"

Test Login:

  1. Click "Sign In"
  2. Enter same credentials
  3. Click "SIGN IN"
  4. Should see: "Login successful!"
  5. Check browser console - token should be logged

Test Protected Route (Postman):

  1. Copy token from login response
  2. Create GET request to http://localhost:5000/api/auth/profile
  3. Add header: Authorization: Bearer YOUR_TOKEN
  4. Send request
  5. Should receive user profile data

🚀 Deployment

Backend Deployment (Example: Heroku)

# Install Heroku CLI
npm install -g heroku

# Login
heroku login

# Create app
heroku create your-app-name

# Set environment variables
heroku config:set DB_HOST=your-mysql-host
heroku config:set DB_USER=your-db-user
heroku config:set DB_PASSWORD=your-db-password
heroku config:set JWT_SECRET=your-secret-key

# Deploy
git push heroku main

Frontend Deployment (Example: Netlify)

# Build production version
npm run build

# Deploy to Netlify (drag & drop build folder)
# Or use Netlify CLI
npm install -g netlify-cli
netlify deploy --prod

Environment Variables for Production

Backend (.env):

PORT=5000
DB_HOST=your-production-db-host
DB_USER=your-production-user
DB_PASSWORD=your-secure-password
DB_NAME=auth_system
JWT_SECRET=your-very-long-random-secure-secret-key
JWT_EXPIRE=7d
NODE_ENV=production

Frontend: Update API URL to production backend:

const API_URL = 'https://your-backend-api.com/api/auth';

📚 Future Enhancements

  • Password reset functionality
  • Email verification
  • OAuth (Google, Facebook, GitHub)
  • Two-factor authentication (2FA)
  • User profile management
  • Remember me functionality
  • Rate limiting for API endpoints
  • Refresh token mechanism
  • User roles and permissions
  • Account deletion
  • Password strength indicator
  • Email notifications
  • Activity logs

🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


👨‍💻 Author

Anila Nawaz


🙏 Acknowledgments


📞 Support

If you have any questions or issues, please:

  1. Check the Troubleshooting section
  2. Search existing issues on GitHub
  3. Create a new issue with detailed information

⭐ Show Your Support

If you found this project helpful, please give it a ⭐ on GitHub!


Made with ❤️ and ☕

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors