Personal Fullstack Project β Backend
A secure, modular, and extensible Node.js backend built with Express, MongoDB, and JWT, powering the authentication logic of a MERN-based fullstack application.
π‘ Follows modern best practices, with structured logging and OAuth integrations.
π Frontend repository: mern-auth-frontend
This is the backend API that supports a full authentication flow for a MERN-based application.
Supports a full authentication flow, including JWT and OAuth logins, user account management, and secure route protection for MERN-based apps.
You can try the full app here:
π mern-auth-frontend-beta-two.vercel.app
β οΈ Note: The service may be temporarily unavailable due to a MongoDB Atlas free-tier cluster outage or external infrastructure issues. Authentication features might not work until service is restored.
When opening the app for the first time, the backend server may take up to one minute to respond, as it's hosted on a free-tier platform with cold start delays.
β οΈ Safari Users: Due to cross-site cookie restrictions in Safari, authentication may not work properly out of the box.
Please either:
- Use Chrome or Firefox for the full experience
- Or enable third-party cookies in Safari settings (Settings β Privacy β Uncheck βPrevent cross-site trackingβ)
You can access the deployed backend here:
π https://mern-auth-server-o28m.onrender.com
Use this to test the frontend or API routes directly (e.g. via Postman or browser dev tools).
Clone the repository and install dependencies:
git clone https://github.com/n1kFord/mern-auth-server.git
cd mern-auth-server
npm install
npm startMake sure your MongoDB instance is running and configured properly.
Create a .env file in the root with the following:
PORT=8080
MONGO_URI=your_mongo_connection_string
CLIENT_URI=your_frontend_uri
JWT_SECRET=your_jwt_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_REDIRECT_URI=http://localhost:8080/api/auth/google/callback
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
GITHUB_REDIRECT_URI=http://localhost:8080/api/auth/github/callbackAdjust values as needed for your local or production environment.
- π JWT-based authentication (register, login, logout)
- π OAuth 2.0 login with Google and GitHub
- π€ User profile updates: change username/password, delete account
- πΌοΈ Avatar support: local or OAuth-derived
- π§± Modular Express structure with separation of concerns
- π Request validation and rate-limiting
- π§° Structured logs with
winston(console + file) - β»οΈ Secure environment variable management with
dotenv - π§ͺ Full test coverage using Jest + Supertest for all critical flows
- π‘ ES Modules (
.mjs) with Babel support
POST /api/auth/registerβ Register a new userPOST /api/auth/loginβ Log in with email and passwordGET /api/auth/logoutβ Log out (clears the JWT cookie)GET /api/auth/meβ Get current authenticated userGET /api/auth/googleβ Redirect to Google OAuthGET /api/auth/google/callbackβ Handle Google OAuth callbackGET /api/auth/githubβ Redirect to GitHub OAuthGET /api/auth/github/callbackβ Handle GitHub OAuth callback
Requires authentication (JWT in HTTP-only cookie)
POST /api/user/change-usernameβ Change usernamePOST /api/user/change-passwordβ Change passwordDELETE /api/user/delete-accountβ Delete user account
This API uses JWT-based authentication with tokens stored in HTTP-only cookies.
To access protected routes, the client must include the JWT cookie in the request.
Example middleware:
import jwt from "jsonwebtoken";
import logger from "../utils/logger.mjs";
export const authenticateUser = (req, res, next) => {
const token = req.cookies.token;
if (!token) {
logger.warn(
\`No token provided for \${req.method} \${req.originalUrl} | IP: \${req.ip}\`,
);
return res.status(401).json({ msg: "No token, authorization denied" });
}
try {
const decoded = jwt.verify(
token,
process.env.JWT_SECRET || "my-secret",
);
req.userId = decoded.userId;
next();
} catch (error) {
logger.error(
\`Invalid token provided for \${req.method} \${req.originalUrl} | IP: \${req.ip} | Error: \${error.message}\`,
);
return res.status(401).json({ msg: "Token is not valid" });
}
};| Category | Stack / Library |
|---|---|
| Runtime | Node.js |
| Framework | Express |
| Database | MongoDB + Mongoose |
| Auth | JWT, Google OAuth, GitHub OAuth |
| Logging | Winston |
| Middleware | express-rate-limit, cors, helmet |
| Tooling | dotenv, babel, nodemon |
| Testing | Jest, Supertest |
npm run dev # Start dev server with nodemon
npm start # Start server (production)
npm test # Run Jest tests with logging to logs/tests.logNote: The test script clears logs/tests.log before each run:
Tests are written using Jest and supertest, covering registration, login, protected routes, and user actions such as updating username, changing password, and deleting the account.
Each test suite:
- Initializes a test MongoDB instance
- Cleans up test data afterward
- Uses realistic HTTP requests and assertions
All tests run with logging redirected to
logs/tests.logfor better debugging.
server/
βββ logs/ # Winston log files
βββ src/
β βββ controllers/ # Express route handlers
β βββ middlewares/ # Custom middlewares (auth, logging, rate-limit)
β βββ models/ # Mongoose models
β βββ routes/ # Route definitions (auth, user, etc.)
β βββ tests/ # Jest test files
β βββ utils/ # Utility functions (JWT, logging, etc.)
β βββ index.mjs # Entry point (Express app + server startup)
βββ .env # Environment variables
βββ .babelrc # Babel config
βββ .prettierrc # Prettier config
βββ jest.config.mjs # Jest config
βββ package.json
βββ package-lock.json
βββ LICENSE
This project is licensed under the MIT License β feel free to use, modify, and distribute with attribution.
π‘ Created with care by @n1kFord