# CipherGuard — Secure Login System

A production-ready, full-stack secure authentication system built for a cybersecurity
coursework/internship project. Demonstrates industry-standard practices for
authentication, authorization, and web application hardening.

**Stack:** React.js (Vite) · Node.js · Express.js · MongoDB · JWT · bcrypt · express-validator

---

## 1. Folder structure

```
cipherguard/
├── backend/
│   ├── config/
│   │   └── db.js                  # MongoDB connection
│   ├── controllers/
│   │   └── authController.js      # register, login, refresh, logout, password reset
│   ├── middleware/
│   │   ├── auth.js                # JWT verification (protect)
│   │   ├── roleCheck.js           # role-based access control (authorize)
│   │   ├── validators.js          # express-validator rule sets
│   │   ├── rateLimiter.js         # brute-force / abuse throttling
│   │   └── errorHandler.js        # centralized error responses
│   ├── models/
│   │   └── User.js                # Mongoose schema + bcrypt hashing hook
│   ├── routes/
│   │   ├── authRoutes.js
│   │   └── userRoutes.js
│   ├── utils/
│   │   └── generateToken.js       # access/refresh JWT helpers
│   ├── .env.example
│   ├── package.json
│   └── server.js                  # security middleware stack + app bootstrap
│
├── frontend/
│   ├── public/
│   ├── src/
│   │   ├── components/
│   │   │   ├── ProtectedRoute.jsx
│   │   │   ├── PasswordStrengthMeter.jsx
│   │   │   └── DecryptText.jsx
│   │   ├── context/
│   │   │   └── AuthContext.jsx
│   │   ├── pages/
│   │   │   ├── Login.jsx
│   │   │   ├── Register.jsx
│   │   │   ├── ForgotPassword.jsx
│   │   │   └── Dashboard.jsx
│   │   ├── services/
│   │   │   └── api.js             # axios instance, CSRF + token-refresh handling
│   │   ├── styles/
│   │   │   └── theme.css          # dark cybersecurity theme
│   │   ├── App.jsx
│   │   └── main.jsx
│   ├── index.html
│   ├── package.json
│   └── vite.config.js
│
├── README.md
└── SECURITY.md                    # security control explanations
```

---

## 2. Database schema (MongoDB / Mongoose)

```js
User {
  _id: ObjectId,
  fullName: String,        // required, 2–100 chars
  email: String,           // required, unique, lowercase
  password: String,        // bcrypt hash, never returned in API responses
  role: "user" | "admin",  // default "user"
  failedLoginAttempts: Number,
  lockUntil: Date,
  refreshTokenHash: String,
  passwordResetTokenHash: String,
  passwordResetExpires: Date,
  createdAt: Date,
  updatedAt: Date
}
```

---

## 3. Installation guide

### Prerequisites
- Node.js 18+
- MongoDB running locally (or a MongoDB Atlas connection string)

### Backend setup

```bash
cd backend
npm install
cp .env.example .env
# Edit .env: set MONGO_URI and generate strong random secrets for
# JWT_SECRET, JWT_REFRESH_SECRET, COOKIE_SECRET, CSRF_SECRET, e.g.:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"

npm run dev        # starts on http://localhost:5000
```

### Frontend setup

```bash
cd frontend
npm install
npm run dev         # starts on http://localhost:3000
```

The Vite dev server proxies `/api/*` requests to `http://localhost:5000`, so open
`http://localhost:3000` and the frontend and backend will talk to each other with
cookies working correctly (same-origin from the browser's point of view).

### Creating an admin user

By default every registered account gets `role: "user"`. To test role-based
access control, manually promote a user in MongoDB:

```js
db.users.updateOne({ email: "admin@example.com" }, { $set: { role: "admin" } })
```

---

## 4. API reference

| Method | Route                       | Auth required | Description                          |
|--------|------------------------------|----------------|---------------------------------------|
| GET    | `/api/csrf-token`            | No             | Issue a CSRF token for the session    |
| POST   | `/api/auth/register`         | No             | Create a new account                  |
| POST   | `/api/auth/login`            | No             | Log in, sets httpOnly cookies         |
| POST   | `/api/auth/refresh`          | No (refresh cookie) | Rotate access/refresh tokens     |
| POST   | `/api/auth/logout`           | Yes            | Revoke refresh token, clear cookies   |
| GET    | `/api/auth/me`               | Yes            | Get current authenticated user        |
| POST   | `/api/auth/forgot-password`  | No             | Request a password reset link         |
| POST   | `/api/auth/reset-password`   | No (reset token)| Set a new password                   |
| GET    | `/api/users/dashboard`       | Yes            | Protected dashboard data              |
| GET    | `/api/users`                 | Yes (admin)    | List all users — RBAC demo            |

All authentication state travels via **httpOnly, secure, SameSite=strict cookies** —
the frontend never stores tokens in `localStorage` or `sessionStorage`.

---

## 5. Deploying with HTTPS

In production, terminate TLS at a reverse proxy (recommended) or directly in Node:

**Option A — reverse proxy (recommended):** run the Express app on `localhost:5000`
behind Nginx or Caddy, which handles the TLS certificate (e.g. via Let's Encrypt /
Certbot) and forwards traffic over HTTP internally. Set `app.set("trust proxy", 1)`
(already done in `server.js`) so secure cookies and IP-based rate limiting work
correctly behind the proxy.

**Option B — TLS directly in Node:**
```js
const https = require("https");
const fs = require("fs");

https.createServer({
  key: fs.readFileSync("/path/to/privkey.pem"),
  cert: fs.readFileSync("/path/to/fullchain.pem"),
}, app).listen(443);
```

Either way, set `NODE_ENV=production` so `server.js` marks cookies `secure: true`
(sent only over HTTPS) and Helmet's HSTS header is honored by browsers.

See **SECURITY.md** for a full breakdown of every control and why it matters.
