Secure Authentication in CampusX Using JWT

Introduction Authentication is a critical part of any web application. In CampusX, we use JWT (JSON Web Tokens) to handle user authentication efficiently and securely. JWT provides a stateless way to verify users while minimizing database queries. This blog explains: What JWT is and why it's important. How CampusX uses access and refresh tokens. How token refreshing ensures seamless user experience. What is JWT? JWT is a compact and self-contained token format used for securely transmitting information between parties as a JSON object. It consists of three parts: Header – Contains metadata like token type and signing algorithm. Payload – Stores claims (user information, expiry time, etc.). Signature – Ensures token integrity using a secret key. Example of a JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiIxMjM0IiwiaWF0IjoxNjExNjE2MDB9 .4xvNcTkORHj9xE8TftRkEw7sdJjxUX9PYG6xRJOnhZk JWT is commonly used for authentication because it eliminates the need for session storage and repeated database queries. Access & Refresh Tokens in CampusX CampusX uses access tokens for authentication and refresh tokens for renewing access tokens without requiring the user to log in again. 1. Generating Tokens const generateAccessAndRefreshTokens = async (userId) => { try { const user = await User.findById(userId); const accessToken = user.generateAccessToken(); const refreshToken = user.generateRefreshToken(); user.refreshToken = refreshToken; await user.save({ validateBeforeSave: false }); return { accessToken, refreshToken }; } catch (error) { throw new ApiError( STATUS_CODES.INTERNAL_ERROR, "Error generating access and refresh tokens" ); } }; Here, the user's access and refresh tokens are generated and stored securely. JWT Authentication Middleware The verifyJWT middleware protects routes by verifying JWT tokens before allowing access. export const verifyJWT = AsyncHandler(async (req, res, next) => { try { const token = req.cookies?.accessToken || req.header("Authorization")?.replace("Bearer ", ""); if (!token) { throw new ApiError(401, "Unauthorized request"); } const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); const user = await User.findById(decodedToken._id).select("-password -refreshToken"); if (!user) { throw new ApiError(402, "Invalid access token"); } req.user = user; next(); } catch (error) { throw new ApiError(401, "Token expired"); } }); This ensures only authenticated users can access protected resources. Refreshing Expired Tokens If the access token expires, CampusX uses the refresh token to generate a new access token, avoiding user logouts. const refreshAccessToken = AsyncHandler(async (req, res) => { const incomingRefreshToken = req.cookies.refreshToken || req.body.refreshToken; if (!incomingRefreshToken) { throw new ApiError(STATUS_CODES.UNAUTHORIZED, "Refresh token not found"); } try { const decodedToken = jwt.verify(incomingRefreshToken, process.env.REFRESH_TOKEN_SECRET); const user = await User.findById(decodedToken._id); if (!user || incomingRefreshToken !== user.refreshToken) { throw new ApiError(STATUS_CODES.UNAUTHORIZED, "Invalid refresh token"); } const { accessToken, refreshToken } = await generateAccessAndRefreshTokens(user._id); res .status(STATUS_CODES.OK) .cookie("accessToken", accessToken, { httpOnly: true, secure: true }) .cookie("refreshToken", refreshToken, { httpOnly: true, secure: true }) .json(new ApiResponse(STATUS_CODES.OK, { accessToken, refreshToken }, "Access token refreshed")); } catch (error) { throw new ApiError(STATUS_CODES.INTERNAL_ERROR, "Error refreshing access token: " + error.message); } }); Fetching User on Page Refresh CampusX calls fetchUser on every page load to refresh expired access tokens. const fetchUser = async () => { try { const res = await axiosInstance.get("/users/current-user"); setUser(res.data?.data?.user); } catch (err) { if (err.response?.status === 401) { setUser(null); } if (err.response?.status === 403) { console.log("Access Token Expired, Refreshing..."); try { await axiosInstance.post("/users/refresh-token"); return fetchUser(); // Retry the original request } catch (refreshErr) { toast.error("Session expired, Please login again!"); } } throw err; } }; How it Works: Calls /users/current-user to check if the user is logged in. If the access token is expired (403 error), it tries to refresh it using /users/refresh-token. If refreshing fails, prompts the user to log in again. Conclusion JWT authentication in CampusX ensures: ✅ Secure user authentication. ✅ Efficient token-based sessio

Mar 14, 2025 - 15:42
 0
Secure Authentication in CampusX Using JWT

Introduction

Authentication is a critical part of any web application. In CampusX, we use JWT (JSON Web Tokens) to handle user authentication efficiently and securely. JWT provides a stateless way to verify users while minimizing database queries.

This blog explains:

  • What JWT is and why it's important.
  • How CampusX uses access and refresh tokens.
  • How token refreshing ensures seamless user experience.

What is JWT?

JWT is a compact and self-contained token format used for securely transmitting information between parties as a JSON object. It consists of three parts:

  1. Header – Contains metadata like token type and signing algorithm.
  2. Payload – Stores claims (user information, expiry time, etc.).
  3. Signature – Ensures token integrity using a secret key.

Example of a JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiIxMjM0IiwiaWF0IjoxNjExNjE2MDB9
.4xvNcTkORHj9xE8TftRkEw7sdJjxUX9PYG6xRJOnhZk

JWT is commonly used for authentication because it eliminates the need for session storage and repeated database queries.

Access & Refresh Tokens in CampusX

CampusX uses access tokens for authentication and refresh tokens for renewing access tokens without requiring the user to log in again.

1. Generating Tokens

const generateAccessAndRefreshTokens = async (userId) => {
  try {
    const user = await User.findById(userId);
    const accessToken = user.generateAccessToken();
    const refreshToken = user.generateRefreshToken();

    user.refreshToken = refreshToken;
    await user.save({ validateBeforeSave: false });

    return { accessToken, refreshToken };
  } catch (error) {
    throw new ApiError(
      STATUS_CODES.INTERNAL_ERROR,
      "Error generating access and refresh tokens"
    );
  }
};

Here, the user's access and refresh tokens are generated and stored securely.

JWT Authentication Middleware

The verifyJWT middleware protects routes by verifying JWT tokens before allowing access.

export const verifyJWT = AsyncHandler(async (req, res, next) => {
  try {
    const token = req.cookies?.accessToken || req.header("Authorization")?.replace("Bearer ", "");
    if (!token) {
      throw new ApiError(401, "Unauthorized request");
    }

    const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);
    const user = await User.findById(decodedToken._id).select("-password -refreshToken");
    if (!user) {
      throw new ApiError(402, "Invalid access token");
    }

    req.user = user;
    next();
  } catch (error) {
    throw new ApiError(401, "Token expired");
  }
});

This ensures only authenticated users can access protected resources.

Refreshing Expired Tokens

If the access token expires, CampusX uses the refresh token to generate a new access token, avoiding user logouts.

const refreshAccessToken = AsyncHandler(async (req, res) => {
  const incomingRefreshToken = req.cookies.refreshToken || req.body.refreshToken;
  if (!incomingRefreshToken) {
    throw new ApiError(STATUS_CODES.UNAUTHORIZED, "Refresh token not found");
  }

  try {
    const decodedToken = jwt.verify(incomingRefreshToken, process.env.REFRESH_TOKEN_SECRET);
    const user = await User.findById(decodedToken._id);

    if (!user || incomingRefreshToken !== user.refreshToken) {
      throw new ApiError(STATUS_CODES.UNAUTHORIZED, "Invalid refresh token");
    }

    const { accessToken, refreshToken } = await generateAccessAndRefreshTokens(user._id);
    res
      .status(STATUS_CODES.OK)
      .cookie("accessToken", accessToken, { httpOnly: true, secure: true })
      .cookie("refreshToken", refreshToken, { httpOnly: true, secure: true })
      .json(new ApiResponse(STATUS_CODES.OK, { accessToken, refreshToken }, "Access token refreshed"));
  } catch (error) {
    throw new ApiError(STATUS_CODES.INTERNAL_ERROR, "Error refreshing access token: " + error.message);
  }
});

Fetching User on Page Refresh

CampusX calls fetchUser on every page load to refresh expired access tokens.

const fetchUser = async () => {
  try {
    const res = await axiosInstance.get("/users/current-user");
    setUser(res.data?.data?.user);
  } catch (err) {
    if (err.response?.status === 401) {
      setUser(null);
    }
    if (err.response?.status === 403) {
      console.log("Access Token Expired, Refreshing...");
      try {
        await axiosInstance.post("/users/refresh-token");
        return fetchUser(); // Retry the original request
      } catch (refreshErr) {
        toast.error("Session expired, Please login again!");
      }
    }
    throw err;
  }
};

How it Works:

  1. Calls /users/current-user to check if the user is logged in.
  2. If the access token is expired (403 error), it tries to refresh it using /users/refresh-token.
  3. If refreshing fails, prompts the user to log in again.

Conclusion

JWT authentication in CampusX ensures:
✅ Secure user authentication.

✅ Efficient token-based session management.

✅ Seamless token refresh without re-login.

By implementing access & refresh tokens, CampusX provides a smooth user experience while maintaining strong security.