A full-stack cloud file storage application with secure JWT authentication, built with Spring Boot and Vue.js 3.
A modern, secure file storage system that allows users to upload, manage, and share files with a beautiful, responsive interface. Features include JWT authentication, real-time upload progress, media previews, and dark/light themes.
- JWT Authentication with refresh tokens
- BCrypt password hashing
- File ownership verification
- Path traversal protection
- CORS restrictions
- httpOnly cookies for refresh tokens
- Upload files up to 3GB
- Download files
- Preview images, videos, audio, PDFs, and text files
- Delete files with confirmation
- View storage usage
- User-specific file isolation
- Responsive design (mobile, tablet, desktop)
- Dark/Light theme toggle
- Real-time upload progress bar
- Themed modal dialogs
- Smooth animations
- Intuitive navigation
- Blob URL caching for media
- Lazy loading of routes
- Code splitting
- Memory leak prevention
- Optimized builds
βββββββββββββββββββ HTTP/REST βββββββββββββββββββ
β β ββββββββββββββββββββββββββΊ β β
β Vue.js 3 β JWT Authentication β Spring Boot β
β Frontend β β Backend β
β (Port 5173) β β (Port 8080) β
β β β β
βββββββββββββββββββ ββββββββββ¬βββββββββ
β
β
βΌ
βββββββββββββββββ
β MongoDB β
β (Port 27017) β
βββββββββββββββββ
- Java 17
- Spring Boot 3.1.5
- Spring Security - Authentication & Authorization
- Spring Data MongoDB - Database operations
- JJWT 0.11.5 - JWT tokens
- Maven - Build tool
- Vue.js 3 - Progressive framework
- Vite - Build tool
- Vue Router - Routing
- Pinia - State management
- Axios - HTTP client
- Lucide Vue Next - Icons
- MongoDB 4.4+ - NoSQL database
- Java 17 or higher
- Maven 3.6+
- Node.js 16+ and npm 8+
- MongoDB 4.4+
git clone <repository-url>
cd APP# Using Docker
docker run -d -p 27017:27017 --name mongodb mongo:latest
# Or use local MongoDB
mongodEdit backend/src/main/resources/application.properties:
# IMPORTANT: Change this in production!
jwt.secret=YOUR_SECRET_KEY_HERE_MIN_256_BITScd backend
# Build and run
./mvnw clean install
./mvnw spring-boot:runBackend will run on http://localhost:8080
Create frontend/.env:
VITE_API_URL=http://localhost:8080cd frontend
npm install
npm run devFrontend will run on http://localhost:5173
Open your browser and navigate to http://localhost:5173
sequenceDiagram
participant User
participant Frontend
participant Backend
participant MongoDB
User->>Frontend: Enter credentials
Frontend->>Backend: POST /login
Backend->>MongoDB: Verify user
MongoDB-->>Backend: User data
Backend-->>Frontend: Access token + Refresh token (cookie)
Frontend->>Frontend: Store access token in sessionStorage
Note over Frontend,Backend: Making authenticated requests
Frontend->>Backend: GET /files (with JWT header)
Backend->>Backend: Validate JWT
Backend->>MongoDB: Fetch user's files
MongoDB-->>Backend: File list
Backend-->>Frontend: JSON response
Note over Frontend,Backend: Token refresh
Frontend->>Backend: POST /refresh (with refresh token cookie)
Backend->>MongoDB: Verify refresh token
MongoDB-->>Backend: Token valid
Backend-->>Frontend: New access token
curl -X POST http://localhost:8080/register \
-H "Content-Type: application/json" \
-d '{"username":"john","password":"secret123"}'Response:
{
"message": "User registered successfully"
}curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"john","password":"secret123"}' \
-c cookies.txtResponse:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"username": "john",
"message": "Login successful"
}curl -X POST http://localhost:8080/upload \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-F "file=@document.pdf" \
-b cookies.txtcurl -X GET http://localhost:8080/files \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-b cookies.txtResponse:
[
{
"id": "507f1f77bcf86cd799439011",
"filename": "document.pdf",
"contentType": "application/pdf",
"size": 1048576,
"uploadDate": "2024-01-15T10:30:00Z",
"ownerId": "user123"
}
]The frontend uses Axios interceptors for seamless JWT integration:
// Request Interceptor - Add JWT to all requests
axios.interceptors.request.use(config => {
const authStore = useAuthStore()
if (authStore.accessToken) {
config.headers.Authorization = `Bearer ${authStore.accessToken}`
}
return config
})
// Response Interceptor - Handle token refresh
axios.interceptors.response.use(
response => response,
async error => {
if (error.response?.status === 401) {
// Token expired, try to refresh
const newToken = await authStore.refreshAccessToken()
if (newToken) {
// Retry original request with new token
error.config.headers.Authorization = `Bearer ${newToken}`
return axios(error.config)
}
}
throw error
}
)Backend allows requests from frontend origin:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}APP/
βββ backend/ # Backend (Spring Boot)
β βββ src/
β β βββ main/
β β βββ java/
β β β βββ com/example/filestorage/
β β β βββ controller/ # REST controllers
β β β βββ model/ # Entity models
β β β βββ repository/ # MongoDB repositories
β β β βββ security/ # Security configuration
β β β βββ service/ # Business logic
β β β βββ exception/ # Error handling
β β βββ resources/
β β βββ application.properties
β βββ uploads/ # File storage directory
β βββ pom.xml # Maven configuration
β βββ README.md # Backend documentation
βββ frontend/ # Frontend (Vue.js)
β βββ src/
β β βββ components/ # Reusable components
β β βββ views/ # Page components
β β βββ stores/ # Pinia stores
β β βββ router/ # Vue Router
β β βββ config/ # Configuration
β βββ .env # Environment variables
β βββ vite.config.js # Vite configuration
β βββ README.md # Frontend documentation
βββ README.md # This file (Main documentation)
- Change
jwt.secretto a strong, random value (min 256 bits) - Use environment variables for sensitive data
- Enable HTTPS/TLS
- Update CORS to production frontend URL
- Set secure cookie flags (
Secure,SameSite) - Implement rate limiting
- Enable MongoDB authentication
- Use strong MongoDB passwords
- Implement file type validation
- Add virus scanning for uploads
- Set up logging and monitoring
- Regular security audits
export SPRING_DATA_MONGODB_URI=mongodb://prod-server:27017/filestorage
export JWT_SECRET=your-production-secret-key-min-256-bits
export SERVER_PORT=8080export VITE_API_URL=https://api.yourapp.comcd backend
./mvnw clean package -DskipTests
java -jar target/filestorage-0.0.1-SNAPSHOT.jarFROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]cd frontend
npm run buildvercel --prodnetlify deploy --prod --dir=dist{
"_id": "ObjectId",
"username": "string",
"password": "string (bcrypt)",
"roles": ["USER"]
}{
"_id": "ObjectId",
"filename": "string",
"contentType": "string",
"size": "number",
"uploadDate": "date",
"ownerId": "string"
}{
"_id": "ObjectId",
"token": "string (JWT)",
"username": "string",
"expiryDate": "instant",
"createdDate": "instant"
}cd backend
./mvnw testcd frontend
npm run test1. CORS Errors
- Ensure backend
SecurityConfigallows frontend origin - Check that
withCredentials: trueis set in Axios
2. 401 Unauthorized
- Verify JWT token is being sent in Authorization header
- Check if token has expired
- Try logging out and logging back in
3. File Upload Fails
- Check file size limits in both frontend and backend
- Verify
uploads/directory exists and is writable - Check MongoDB connection
4. MongoDB Connection Failed
- Ensure MongoDB is running
- Verify connection string in
application.properties - Check MongoDB port (default: 27017)
For detailed API documentation, see:
Contributions, issues, and feature requests are welcome!
Sreenath
Happy Coding! π