-1

I am learning Expressjs, so today i was looking at bcrypt, jsonwebtoken. so i created this after all the readings but after login the server console has this

> [email protected] start
> nodemon server.js

[nodemon] 3.1.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node server.js`
Server running on port 5000
Connected to the database as id 123
Authorization Header: undefined
Token: undefined
No token provided

.env

PORT=5000
ACCESS_TOKEN_SECRET=61ba47d9af34a25e73da8349cf628ab4

Database mysql connection

const mysql = require("mysql");

const connection = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "xxxxxxxx",
    database: "web_dev_classroom",
});

connection.connect((err) => {
    if (err) {
        console.error("Error connecting to the database:", err.stack);
        return;
    }
    console.log("Connected to the database as id " + connection.threadId);
});

module.exports = connection;

server.js

const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const connection = require("./db");
const dotenv = require("dotenv");
const path = require("path");
const cors = require("cors");
dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static("public"));
app.use(cors()); // Use cors middleware to enable CORS for all routes

// app.use(
//     cors({
//         origin: "*",
//         methods: ["GET", "POST"],
//         allowedHeaders: ["Content-Type", "Authorization"],
//     })
// );

// -------------------------------------------Routes-------------------------------------
// Serve home page
app.get("/", (req, res) => {
    res.sendFile(path.join(__dirname, "views", "index.html"));
});

// Serve signup page
app.get("/signup.html", (req, res) => {
    res.sendFile(path.join(__dirname, "views", "signup.html"));
});

// Serve login page
app.get("/login.html", (req, res) => {
    res.sendFile(path.join(__dirname, "views", "login.html"));
});

// Signup route
app.post("/signup", async (req, res) => {
    const {
        username,
        password,
        email,
        course_type,
        state_of_origin,
        phone_no,
    } = req.body;
    try {
        // Check if email already exists
        connection.query(
            "SELECT * FROM users WHERE email = ?",
            [email],
            async (err, results) => {
                if (err) throw err;
                if (results.length > 0) {
                    return res
                        .status(400)
                        .json({ message: "Email already in use" });
                }

                const hashedPassword = await bcrypt.hash(password, 10);
                connection.query(
                    "INSERT INTO users (username, password, email, course_type, state_of_origin, phone_no) VALUES (?, ?, ?, ?, ?, ?)",
                    [
                        username,
                        hashedPassword,
                        email,
                        course_type,
                        state_of_origin,
                        phone_no,
                    ],
                    (err, results) => {
                        if (err) throw err;
                        res.status(201).json({
                            message: "User registered successfully",
                        });
                    }
                );
            }
        );
    } catch (error) {
        console.error(error);
        res.status(500).json({ message: "Server error" });
    }
});

// Login route
app.post("/login", async (req, res) => {
    const { email, password } = req.body;
    connection.query(
        "SELECT * FROM users WHERE email = ?",
        [email],
        async (err, results) => {
            if (err) return res.status(500).json({ message: "Server error" });
            if (results.length === 0) {
                return res.status(400).json({ message: "User not found" });
            } else {
                const user = results[0];
                const isMatch = await bcrypt.compare(password, user.password);
                if (isMatch) {
                    const accessToken = jwt.sign(
                        { id: user.id, username: user.username },
                        process.env.ACCESS_TOKEN_SECRET,
                        { expiresIn: "2h" }
                    );
                    return res.json({ accessToken });
                } else {
                    return res
                        .status(401)
                        .json({ message: "Incorrect password" });
                }
            }
        }
    );
});

// Protected route
app.get("/classroom.html", authenticateToken, (req, res) => {
    console.log("Headers received:", req.headers);
    res.sendFile(path.join(__dirname, "views", "classroom.html"));
});

// -------------------------------------------Routes Ends -------------------------------------

// Middleware to authenticate JWT token
function authenticateToken(req, res, next) {
    const authHeader = req.headers["authorization"];
    console.log("Authorization Header:", authHeader);

    const token = authHeader && authHeader.split(" ")[1];
    console.log("Token:", token); // Log the extracted token

    if (!token) {
        console.log("No token provided");
        return res.sendStatus(401);
    }

    jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
        if (err) {
            console.error("JWT verification error:", err);
            return res.sendStatus(403); // 403 for token expired or invalid
        }
        req.user = user;
        console.log("Authenticated user:", user); // Log the authenticated user
        next();
    });
}

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

login.html and .js

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Login</title>
        <link rel="stylesheet" href="/styles/style.css" />
    </head>
    <body>
        <h1>Login</h1>
        <form id="loginForm">
            <label for="email">Email:</label>
            <input type="email" id="email" name="email" required />
            <label for="password">Password:</label>
            <input type="password" id="password" name="password" required />
            <button type="submit">Login</button>
        </form>
        <script src="/scripts/login.js"></script>
    </body>
</html>


document.getElementById("loginForm").addEventListener("submit", async (e) => {
    e.preventDefault();
    const email = document.getElementById("email").value;
    const password = document.getElementById("password").value;

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

        if (response.ok) {
            const data = await response.json();
            if (data.accessToken) {
                localStorage.setItem("accessToken", data.accessToken);
                console.log(
                    "Token stored:",
                    localStorage.getItem("accessToken")
                );
                alert("Login successful!");
                window.location.href = "/classroom.html";
            } else {
                alert("Login failed");
            }
        } else {
            const error = await response.json();
            alert(`Error: ${error.message}`);
        }
    } catch (error) {
        alert("An error occurred: " + error.message);
    }
});

classroom.html and .js

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Classroom</title>
        <link rel="stylesheet" href="/styles/style.css" />
        <script defer src="/scripts/classroom.js"></script>
    </head>
    <body>
        <h1>Welcome to the Classroom</h1>
        <p>You have successfully logged in!</p>
    </body>
</html>


document.addEventListener("DOMContentLoaded", async () => {
    const token = localStorage.getItem("accessToken");
    console.log("Token retrieved from localStorage:", token); // Log the retrieved token

    if (!token) {
        alert("No access token found, please login first.");
        window.location.href = "/login.html";
        return;
    }

    try {
        const response = await fetch("/classroom", {
            method: "GET",
            headers: {
                Authorization: `Bearer ${token}`,
                "Content-Type": "application/json",
            },
        });

        console.log("Request headers sent:", {
            Authorization: `Bearer ${token}`,
            "Content-Type": "application/json",
        }); // Log the headers sent with the request

        if (response.ok) {
            const classroomContent = await response.text();
            document.body.innerHTML = classroomContent;
        } else {
            console.error("Unauthorized access. Status code:", response.status);
            alert("Unauthorized access. Please login again.");
            window.location.href = "/login.html";
        }
    } catch (error) {
        console.error("Fetch error:", error);
        alert("An error occurred: " + error.message);
        window.location.href = "/login.html";
    }
});

I tested with Restclient in vscode and it was successful, redirected me to classroom.html

POST http://localhost:5000/login
Content-Type: application/json

{
    "email": "[email protected]",
    "password": "Password2#"
}

###
GET http://localhost:5000/classroom.html
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJPZ2FTb2xvIiwiaWF0IjoxNzIwMzgyNDA0LCJleHAiOjE3MjAzODk2MDR9.EHmd7f9nGx7bc6KrxaQTJYcVIk3Cns3jzWEuthvSRj0

But in browser after successful login, i will have unauthorized 401

GET http://localhost:5000/classroom.html 401 (Unauthorized)

General headers

Request URL:
http://localhost:5000/classroom.html
Request Method:
GET
Status Code:
401 Unauthorized
Remote Address:
[::1]:5000
Referrer Policy:
strict-origin-when-cross-origin

Response header

HTTP/1.1 401 Unauthorized
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/plain; charset=utf-8
Content-Length: 12
ETag: W/"c-dAuDFQrdjS3hezqxDTNgW7AOlYk"
Date: Sun, 07 Jul 2024 20:47:21 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Request header

GET /classroom.html HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Cookie: SL_G_WPT_TO=en; SL_GWPT_Show_Hide_tmp=undefined; SL_wptGlobTipTmp=undefined
Host: localhost:5000
Referer: http://localhost:5000/login.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36
sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"
sec-ch-ua-mobile: ?1
sec-ch-ua-platform: "Android"

I have added logs to see errors and these errors are what I can get.

0

Browse other questions tagged or ask your own question.