LinkVault is a full-stack web application that allows users to securely upload text or files and share them using a unique, hard-to-guess link. The uploaded content is accessible only to users who possess the link and is automatically deleted after a specified expiry time.
The application features a full user authentication system allowing users to create accounts, manage their uploads, and track their content through a personalized dashboard.
The application is inspired by link-based sharing systems such as Pastebin and Google Drive's "anyone with the link" feature.
- Upload plain text or a file (one per upload)
- Generate a unique shareable URL
- Access content strictly via the generated link
- View and copy uploaded text
- Download uploaded files
- Optional password protection for uploads
- View limits - restrict number of times content can be accessed
- Custom expiry times - set when content should automatically delete
- Automatic expiry of content (default: 10 minutes)
- User Registration - Create secure accounts with email and password
- JWT Authentication - Token-based authentication with session persistence
- User Dashboard - View and manage all your uploads in one place
- Content Ownership - Only you can delete your content
- Protected Routes - Secure access to user-specific features
- Guest Mode - Upload without an account (backward compatible)
- Modern glassmorphism design with gradient accents
- Responsive interface that adapts to all screen sizes
- Toast notifications for user feedback
- Drag-and-drop file upload
- Beautiful animations and transitions
- Clean and intuitive navigation
- React (Vite)
- React Router - Client-side routing
- Axios - HTTP requests with interceptors
- CSS3 - Custom styling with glassmorphism effects
- Context API - State management for authentication
- Node.js - Runtime environment
- Express.js - Web framework
- Multer - File upload handling
- bcrypt - Password hashing
- jsonwebtoken - JWT authentication
- Cloudinary - Cloud file storage
- MongoDB Atlas - Cloud database
- Mongoose - ODM for MongoDB
- TTL Indexes - Automatic content expiration
π For detailed architecture diagrams and data flows, see ARCHITECTURE.md
This document includes:
- System architecture overview diagram
- 7 detailed sequence diagrams (registration, login, uploads, dashboard, content access, delete)
- Component interaction tables
- Database schemas
- Security architecture
- User registers with name, email, and password
- Password is hashed using bcrypt (10 salt rounds)
- JWT token is generated and returned to client
- Token is stored in localStorage for session persistence
- Axios interceptors automatically attach token to requests
- Protected routes verify token via middleware
- Expired tokens redirect user to login
- Authenticated Users: Content is associated with user's account via
userId - Guest Users: Content is created with
userId: null - All content gets unique IDs and shareable links
- Content is stored in Cloudinary (files) or database (text)
- TTL index automatically deletes expired content
- Node.js (v14 or higher)
- MongoDB Atlas account
- Cloudinary account
Create a .env file in the backend directory:
# Server Configuration
PORT=3000
# Database
MONGO_URI=your_mongodb_connection_string
# Cloudinary
CLOUDINARY_URL=cloudinary://api_key:api_secret@cloud_name
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# JWT Authentication
JWT_SECRET=your_super_secret_key_change_in_production
JWT_EXPIRE=7d
β οΈ Important: ChangeJWT_SECRETto a long, random string in production!
- Clone the repository
git clone <repository-url>
cd LinkVault- Install backend dependencies
cd backend
npm install- Install frontend dependencies
cd ../frontend
npm install- Configure environment variables
- Create
.envfile inbackend/with the variables listed above
- Start the backend server
cd backend
npm start
# Server runs on http://localhost:3000- Start the frontend development server
cd frontend
npm run dev
# Frontend runs on http://localhost:5173- Access the application
- Open http://localhost:5173 in your browser
Register a new user account.
Request Body:
{
"name": "John Doe",
"email": "[email protected]",
"password": "securepassword123"
}Response:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"_id": "...",
"name": "John Doe",
"email": "[email protected]",
"createdAt": "2026-02-15T19:51:52.021Z"
}
}Login to existing account.
Request Body:
{
"email": "[email protected]",
"password": "securepassword123"
}Response:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"_id": "...",
"name": "John Doe",
"email": "[email protected]",
"createdAt": "2026-02-15T19:51:52.021Z"
}
}Get current user details (requires authentication).
Headers:
Authorization: Bearer <token>
Response:
{
"success": true,
"user": {
"_id": "...",
"name": "John Doe",
"email": "[email protected]",
"createdAt": "2026-02-15T19:51:52.021Z"
}
}Upload text or file. Optional authentication (attaches to user if logged in).
Request:
multipart/form-data- Fields:
text(optional) - Text contentfile(optional) - File to uploadpassword(optional) - Password protectionmaxViews(optional) - View limitexpiry(optional) - Custom expiry date
Headers (Optional):
Authorization: Bearer <token>
Response:
{
"url": "http://localhost:5173/view/<id>"
}Get all content uploaded by authenticated user (requires auth).
Headers:
Authorization: Bearer <token>
Response:
{
"success": true,
"count": 5,
"content": [
{
"_id": "...",
"type": "text",
"text": "Sample content",
"userId": "...",
"createdAt": "2026-02-15T19:51:52.021Z",
"expiresAt": "2026-02-15T20:01:52.021Z"
}
]
}Delete user's own content (requires auth).
Headers:
Authorization: Bearer <token>
Response:
{
"success": true,
"message": "Content deleted successfully"
}View uploaded content (public).
Response:
{
"success": true,
"content": {
"type": "text",
"text": "Sample content",
"createdAt": "2026-02-15T19:51:52.021Z"
}
}MongoDB was chosen due to its flexible schema and built-in support for TTL (Time-To-Live) indexes. TTL indexes allow expired content to be deleted automatically at the database level without requiring background cleanup jobs.
- JWT Tokens: Stateless authentication, no server-side session storage
- bcrypt: Industry-standard password hashing with salt rounds
- Optional Auth: Users can upload without accounts (guest mode)
- Session Persistence: localStorage for seamless user experience
Access control is enforced through multiple layers:
- Link-based access: Secure, randomly generated MongoDB ObjectIDs
- Password protection: Optional bcrypt-hashed passwords for uploads
- Content ownership: Users can only delete their own content
- No public listing: No search or browse functionality
- Protected routes: User dashboard and management require authentication
- Users may optionally specify an expiry date and time
- If no expiry is provided, content expires 10 minutes after upload
- Expired content is automatically deleted by MongoDB TTL index
- Background cleanup job runs every hour as backup
Uploaded files are stored in Cloudinary (cloud storage), while metadata is stored in MongoDB. This design:
- Allows for reliable, scalable file storage
- Provides CDN delivery for fast access
- Supports automatic deletion via Cloudinary API
- Separates concerns (metadata vs. actual files)
- Password Hashing: bcrypt with 10 salt rounds
- JWT Tokens: Signed with secret key, configurable expiration
- Protected Routes: Middleware verification for user endpoints
- Input Validation: Email format, password length requirements
- Password Exclusion: Password field excluded from queries by default
- Ownership Checks: Users can only modify their own content
- CORS: Configured for specific origins
- Token Storage: localStorage with automatic attachment to requests
- 401 Handling: Auto-redirect to login on token expiration
- Protected Routes: Dashboard requires authentication
- No Password Exposure: Passwords never stored client-side
- Secure API Calls: HTTPS-ready configuration
- Navigate to LinkVault
- Click "Sign Up" button
- Enter your name, email, and password (minimum 6 characters)
- Click "Sign Up" to create your account
- You'll be automatically logged in
- Log in to your account
- Upload text or files as usual
- Content is automatically associated with your account
- Access it anytime from your Dashboard
- Upload directly without logging in
- Content is created but not associated with any account
- You'll get a shareable link
- Cannot be managed or deleted later
- Click "Dashboard" in the header
- View all your uploads in a card grid
- Click "View" to access any item
- Click "Delete" to permanently remove items
- Confirm deletion when prompted
- Password Protection: Add a password that viewers must enter
- View Limit: Restrict how many times content can be accessed
- Custom Expiry: Set a specific date/time for auto-deletion
LinkVault/
βββ backend/
β βββ src/
β β βββ models/
β β β βββ User.js # User schema with auth
β β β βββ Content.js # Content schema with userId
β β βββ controllers/
β β β βββ auth.controller.js # Auth endpoints
β β β βββ upload.controller.js # Upload handling
β β β βββ content.controller.js # Content CRUD
β β βββ middleware/
β β β βββ auth.middleware.js # JWT verification
β β βββ routes/
β β β βββ auth.routes.js
β β β βββ upload.routes.js
β β β βββ content.routes.js
β β βββ utils/
β β β βββ cleanup.js # Expired content cleanup
β β βββ app.js # Express app
β β βββ index.js # Server entry point
β βββ .env # Environment variables
β βββ package.json
β
βββ frontend/
βββ src/
β βββ components/
β β βββ Header.jsx # Navigation with auth state
β β βββ ProtectedRoute.jsx # Auth guard
β β βββ UploadForm.jsx # Main upload UI
β β βββ Toast.jsx # Notifications
β βββ contexts/
β β βββ AuthContext.jsx # Auth state management
β β βββ ToastContext.jsx # Toast notifications
β βββ pages/
β β βββ Home.jsx # Upload page
β β βββ Login.jsx # Login form
β β βββ Register.jsx # Registration form
β β βββ Dashboard.jsx # User content management
β β βββ ViewContent.jsx # Content display
β β βββ NotFound.jsx # 404 page
β βββ services/
β β βββ api.js # Axios with interceptors
β βββ styles/
β β βββ Auth.css # Auth pages styling
β β βββ Dashboard.css # Dashboard styling
β β βββ Header.css # Header styling
β β βββ index.css # Global styles
β βββ App.jsx # Main app with routes
β βββ main.jsx # Entry point
βββ package.json
Test the authentication endpoints using curl:
# Register a new user
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"[email protected]","password":"test123"}'
# Login
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"test123"}'
# Get current user (replace <TOKEN> with actual token)
curl http://localhost:3000/api/auth/me \
-H "Authorization: Bearer <TOKEN>"- Open http://localhost:5173
- Test registration flow
- Test login/logout
- Test authenticated uploads
- Test dashboard content management
- Test guest uploads (without login)
Contributions are welcome! Please feel free to submit a Pull Request.
- Inspired by Pastebin and Google Drive
- Built with modern web technologies
- Designed for security and user experience
LinkVault - Secure, Simple, Seamless πβ¨