A production-ready RESTful API for an anonymous messaging platform built with Node.js, Express, MongoDB, and Redis.
| Technology | Purpose |
|---|---|
| Node.js + Express | Server & routing |
| MongoDB + Mongoose | Database |
| Redis | Token blacklisting (logout) |
| JWT | Authentication (Access + Refresh tokens) |
| Bcrypt / Argon2 | Password hashing |
| Nodemailer | OTP & reset password emails |
| Multer | File uploads |
| Google OAuth 2.0 | Social login |
| Node-Cron | Auto-delete unconfirmed users |
- ✅ Signup & Login with email/password
- ✅ Google OAuth 2.0 (signup & login)
- ✅ Email OTP verification with resend + rate limiting
- ✅ 2-Step Verification (2FA) via OTP
- ✅ JWT Access Token (15m) + Refresh Token (1d)
- ✅ Logout (single device via Redis blacklist)
- ✅ Logout from all devices (tokenVersion)
- ✅ Update password
- ✅ Forget password via one-time secure link
- ✅ Profile picture & cover picture upload
- ✅ Profile visit tracking
- ✅ Admin-only endpoints
- ✅ Anonymous messaging with file attachments
- ✅ Auto-delete unconfirmed users after 24 hours (MongoDB TTL)
src/
├── db/
│ ├── models/
│ │ ├── user.models.js
│ │ └── message.model.js
│ ├── enums/
│ │ └── user.enums.js
│ └── db.connection.js
├── modules/
│ ├── authModule/
│ │ ├── auth.controller.js
│ │ ├── auth.service.js
│ │ ├── auth.validation.js
│ │ └── user.repo.js
│ ├── userModule/
│ │ ├── user.controller.js
│ │ ├── user.service.js
│ │ └── upload.validation.js
│ └── messageModule/
│ ├── mes.controller.js
│ └── mes.service.js
├── middleware/
│ ├── auth.middleware.js
│ ├── upload.middleware.js
│ └── validation.middleware.js
├── utils/
│ ├── email.js
│ ├── redisClient.js
│ ├── cronJobs.js
│ └── res.handle.js
└── bootstrap.js
Create config/.env.development with the following:
PORT=3000
MONGO_URI=mongodb://localhost:27017/saraha
TOKEN_SECRET=your_jwt_secret
REFRESH_TOKEN_SECRET=your_refresh_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_email_app_password
REDIS_URL=redis://localhost:6379
FRONTEND_URL=http://localhost:4200# 1. Clone the repo
git clone https://github.com/mohamedmoamen8/saraha-app.git
cd saraha-app
# 2. Install dependencies
npm install
# 3. Start Redis server
redis-server
# 4. Run the app
npm run dev| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /auth/signup |
Register new user | ❌ |
| POST | /auth/login |
Login with email & password | ❌ |
| POST | /auth/verify-otp |
Confirm email with OTP | ❌ |
| POST | /auth/resend-otp |
Resend email OTP (max 5, 1/min) | ❌ |
| POST | /auth/signup/gmail |
Signup/Login with Google | ❌ |
| GET | /auth/profile |
Get logged-in user profile | ✅ |
| PATCH | /auth/update-password |
Update password | ✅ |
| POST | /auth/logout |
Logout from current device | ✅ |
| POST | /auth/logout/all |
Logout from all devices | ✅ |
| POST | /auth/forget-password |
Send password reset link to email | ❌ |
| PATCH | /auth/reset-password |
Reset password via link token | ❌ |
| POST | /auth/enable-2fa |
Send OTP to enable 2FA | ✅ |
| POST | /auth/verify-2fa |
Verify OTP to activate 2FA | ✅ |
| POST | /auth/login-confirm |
Confirm login OTP (2FA users) | ❌ |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /user/profile/:userId |
Upload profile picture | ✅ |
| POST | /user/cover/:userId |
Upload cover picture | ✅ |
| DELETE | /user/profile/:userId |
Delete profile picture | ✅ |
| DELETE | /user/cover/:userId/:imageIndex |
Delete cover picture by index | ✅ |
| GET | /user/visit/:userId |
Visit a user's profile | ✅ |
| GET | /user/visit-count/:userId |
Get profile visit count | ✅ 👑 |
| GET | /user/visit-count-all |
Get all users visit counts | ✅ 👑 |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /message/send-message |
Send a message with attachments | ✅ |
| GET | /message/get-messages |
Get all received messages | ✅ |
All protected routes require a Bearer token in the Authorization header:
Authorization: Bearer <accessToken>
Tokens are issued on login and expire after 15 minutes (access) and 1 day (refresh).
| Feature | Trigger | Expires |
|---|---|---|
| Email confirmation OTP | Signup | 5 minutes |
| Resend OTP | /resend-otp |
5 minutes (max 5 resends) |
| 2FA OTP | /enable-2fa or login |
5 minutes |
| Password reset link | /forget-password |
15 minutes (one-time use) |
Set role: 1 in MongoDB to grant admin access:
db.users.updateOne({ email: "admin@email.com" }, { $set: { role: 1 } })Admin endpoints: view profile visit counts for any user or all users.
| Route | Field | Type | Limit |
|---|---|---|---|
/user/profile/:userId |
profilePicture |
Single image | — |
/user/cover/:userId |
coverPicture |
Single image | Max 2 covers |
/message/send-message |
attachments |
Multiple files | Max 5 files |
Files are stored in the uploads/ directory organized by type.
| Feature | Implementation |
|---|---|
| Password hashing | Argon2 |
| Token blacklisting | Redis (on logout) |
| Logout all devices | tokenVersion increment in DB |
| Reset token security | SHA-256 hashed before DB storage |
| OTP rate limiting | 1 per minute, max 5 resends |
| Unconfirmed user cleanup | MongoDB TTL index (24 hours) |
| Request validation | Joi schemas on all routes |
Import the Saraha App collection and set these environment variables:
| Variable | Value |
|---|---|
baseUrl |
http://localhost:3000 |
TOKEN |
Auto-set after login |
REFRESH_TOKEN |
Auto-set after login |
USER_ID |
Auto-set after profile fetch |
Add to Login request Tests tab to auto-save tokens:
const res = pm.response.json();
pm.environment.set("TOKEN", res.data.accessToken);
pm.environment.set("REFRESH_TOKEN", res.data.refreshToken);Mohamed Moamen
- GitHub: @mohamedmoamen8