Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/khushboodaryani/Chat-App/llms.txt

Use this file to discover all available pages before exploring further.

Chat App uses JSON Web Tokens (JWT) for stateless authentication. When a user signs up or logs in, the server generates a signed JWT and delivers it as an HTTP-only cookie — never exposed to JavaScript — so the client is automatically authenticated on every subsequent request without any manual token management.

How Signup Works

A new account is created by posting five fields to POST /api/auth/signup. The server validates the input, hashes the password, assigns an auto-generated avatar, and sets the JWT cookie before responding. Required fields
fullName
string
required
The user’s display name shown throughout the UI.
username
string
required
Must be unique across all accounts. The server returns 400 if the username is already taken.
password
string
required
Minimum 6 characters. Hashed with bcryptjs using 10 salt rounds before storage.
confirmPassword
string
required
Must match password exactly — validated on both the client (via useSignup) and the server.
gender
string
required
Either "male" or "female". Determines which avatar URL is auto-assigned.
Avatar auto-assignment Profile pictures are sourced from avatar.iran.liara.run and selected by gender and username, so each user gets a consistent, unique avatar without any upload step:
const boyProfilePic  = `https://avatar.iran.liara.run/public/boy?username=${username}`;
const girlProfilePic = `https://avatar.iran.liara.run/public/girl?username=${username}`;

profilePic = gender === "male" ? boyProfilePic : girlProfilePic;
Signup request body
{
  "fullName": "Khushboo Daryani",
  "username": "khushboo",
  "password": "secret123",
  "confirmPassword": "secret123",
  "gender": "female"
}
Signup success response 201 Created
{
  "_id": "664a1f2e8c3b2a001e4f9abc",
  "fullName": "Khushboo Daryani",
  "username": "khushboo",
  "profilePic": "https://avatar.iran.liara.run/public/girl?username=khushboo"
}
The password is never returned in any response. The server selects only _id, fullName, username, and profilePic.

How Login Works

POST /api/auth/login accepts a username and password, verifies the credentials, and issues a fresh JWT cookie on success.
  1. The server calls User.findOne({ username }) to locate the account.
  2. bcrypt.compare(password, user.password) validates the supplied password against the stored hash.
  3. If either check fails the server responds 400 with { "error": "Invalid username or password" } — a deliberately generic message that avoids leaking whether the username exists.
  4. On success, generateTokenAndSetCookie signs a new JWT and attaches it to the response as the jwt cookie.
Login request body
{
  "username": "khushboo",
  "password": "secret123"
}
Login success response 200 OK
{
  "_id": "664a1f2e8c3b2a001e4f9abc",
  "fullName": "Khushboo Daryani",
  "username": "khushboo",
  "profilePic": "https://avatar.iran.liara.run/public/girl?username=khushboo"
}

The token is set by the generateTokenAndSetCookie utility on every successful signup or login:
// backend/utils/generateToken.js
const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
  expiresIn: "15d",
});

res.cookie("jwt", token, {
  maxAge: 15 * 24 * 60 * 60 * 1000, // 15 days in milliseconds
  httpOnly: true,   // not accessible via document.cookie — blocks XSS
  sameSite: "strict", // not sent on cross-site requests — blocks CSRF
  secure: process.env.NODE_ENV !== "development", // HTTPS only in production
});
Security properties at a glance
FlagValuePurpose
httpOnlytrueJavaScript cannot read the cookie, preventing XSS token theft
sameSite"strict"Cookie is never attached to cross-origin requests, preventing CSRF
securetrue in productionCookie is only transmitted over HTTPS when NODE_ENV !== "development"
maxAge15 daysToken expires automatically — no explicit refresh flow needed

Route Protection

All messaging and user endpoints are gated by the protectRoute middleware:
// backend/middleware/protectRoute.js
const token = req.cookies.jwt;

if (!token) {
  return res.status(401).json({ error: "Unauthorized - No Token Provided" });
}

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

const user = await User.findById(decoded.userId).select("-password");

req.user = user; // attached without password field
next();
When the JWT is valid, req.user is populated with the full user document minus the password hash. Every downstream controller can safely read req.user._id, req.user.username, and so on without an additional database call.
If the jwt cookie is missing, expired, or tampered with, the middleware returns 401 Unauthorized and the request never reaches the route handler.

Logout

POST /api/auth/logout immediately invalidates the session by overwriting the cookie with an empty value and a maxAge of 0, which instructs the browser to delete it:
res.cookie("jwt", "", { maxAge: 0 });
res.status(200).json({ message: "Logged out successfully" });
The frontend useLogout hook also removes the cached user object from localStorage and resets authUser to null in the AuthContext, so the app redirects to the login screen.

Frontend Authentication Hooks

All three auth operations are encapsulated in custom React hooks that manage the loading state and surface errors via react-hot-toast.
HookSignatureReturnsSide effects
useSignupsignup({ fullName, username, password, confirmPassword, gender }){ loading, signup }Sets authUser in context; writes to localStorage
useLoginlogin(username, password){ loading, login }Sets authUser in context; writes to localStorage
useLogoutlogout(){ loading, logout }Clears authUser; removes chat-user from localStorage
Example — using useLogin in a component
import useLogin from "../hooks/useLogin";

const LoginForm = () => {
  const { loading, login } = useLogin();

  const handleSubmit = async (e) => {
    e.preventDefault();
    await login(e.target.username.value, e.target.password.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="username" placeholder="Username" />
      <input name="password" type="password" placeholder="Password" />
      <button type="submit" disabled={loading}>
        {loading ? "Logging in…" : "Log In"}
      </button>
    </form>
  );
};

Build docs developers (and LLMs) love