A secure Express.js backend for MinIO that provides multi-user authentication, user-specific bucket management, and strict bucket-level access control. Each user can only access their own buckets, enforced by MinIO bucket policies. The backend uses JWT authentication, PostgreSQL (via Prisma), and MinIO admin credentials for all operations.
backend/
├── prisma/
│ └── schema.prisma # Database schema (User & Bucket models)
├── middleware/
│ └── auth.js # JWT authentication middleware
├── controllers/
│ ├── userController.js # User signup & login
│ └── bucketController.js # Bucket creation, deletion, listing, policy
├── routes/
│ ├── userRoutes.js # Authentication routes
│ └── bucketRoutes.js # Bucket routes (protected)
├── server.js # Main server file
├── package.json # Dependencies and scripts
└── README.md # This file
- Prisma Schema: PostgreSQL models for User and Bucket
- Authentication: JWT-based auth with bcrypt password hashing
- MinIO Integration: Admin-level operations for user and bucket management
- Bucket Policies: Each bucket has a policy allowing only the owner's MinIO access key
- Controllers/Routes: Handle HTTP requests and responses
- User Authentication: Signup and login with JWT tokens
- User-Specific Bucket Access: Each user can only access their own buckets, enforced by MinIO bucket policies
- Bucket Management: Users can create, list, and delete their own buckets
- Bucket Policy Inspection: Users can view the policy for any bucket they own
- Database Integration: PostgreSQL with Prisma ORM
- Input Validation: Using express-validator
- Error Handling: Comprehensive error handling and logging
- Each user is assigned a unique MinIO access key and secret key at signup.
- When a user creates a bucket, a policy is set on that bucket allowing only their access key.
- No other user can access or list another user's buckets.
- The global MinIO admin can access all buckets (for system administration only).
GET /health- Server health statusGET /- API information and available endpoints
POST /api/users/signup
{
"email": "user@example.com",
"password": "password123"
}Response:
{
"success": true,
"message": "User created successfully",
"data": {
"id": "uuid",
"email": "user@example.com",
"minioAccessKey": "user_1234567890_abc123",
"createdAt": "2024-01-01T00:00:00.000Z"
}
}POST /api/users/login
{
"email": "user@example.com",
"password": "password123"
}Response:
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": "uuid",
"email": "user@example.com",
"minioAccessKey": "user_1234567890_abc123",
"createdAt": "2024-01-01T00:00:00.000Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}GET /api/buckets
- Headers:
Authorization: Bearer <jwt_token> - Response: List of buckets owned by the authenticated user.
POST /api/buckets
- Headers:
Authorization: Bearer <jwt_token> - Body:
{
"name": "my-bucket"
}- Response:
{
"success": true,
"message": "Bucket 'my-bucket' created successfully",
"data": { ...bucket info... }
}- Note: The bucket policy is set so only the creator's MinIO access key can access this bucket.
DELETE /api/buckets
- Headers:
Authorization: Bearer <jwt_token> - Body:
{
"name": "my-bucket"
}- Response:
{
"success": true,
"message": "Bucket 'my-bucket' deleted successfully"
}GET /api/buckets/:name/policy
- Headers:
Authorization: Bearer <jwt_token> - Response:
{
"success": true,
"bucket": "my-bucket",
"policy": { ...bucket policy JSON... }
}- Note: Only the bucket owner (or admin) can view the policy.
-
Sign up a new user:
curl -X POST http://localhost:3000/api/users/signup \ -H "Content-Type: application/json" \ -d '{"email": "test@example.com", "password": "password123"}'
-
Login:
curl -X POST http://localhost:3000/api/users/login \ -H "Content-Type: application/json" \ -d '{"email": "test@example.com", "password": "password123"}'
-
Create a bucket (with auth token):
curl -X POST http://localhost:3000/api/buckets \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -d '{"name": "my-test-bucket"}'
-
List user's buckets:
curl -X GET http://localhost:3000/api/buckets \ -H "Authorization: Bearer YOUR_JWT_TOKEN" -
Delete a bucket:
curl -X DELETE http://localhost:3000/api/buckets \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -d '{"name": "my-test-bucket"}'
-
Get a bucket's policy:
curl -X GET http://localhost:3000/api/buckets/my-test-bucket/policy \ -H "Authorization: Bearer YOUR_JWT_TOKEN"
model User {
id String @id @default(uuid())
email String @unique
passwordHash String
minioAccessKey String @unique
minioSecretKey String
createdAt DateTime @default(now())
buckets Bucket[]
}model Bucket {
id String @id @default(uuid())
name String @unique
userId String
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}- Server connects to MinIO using admin credentials
- Admin can create IAM users and assign policies
- Admin creates buckets on behalf of users
- Each user gets a record in PostgreSQL
- Each user gets a MinIO IAM user with:
- Unique accessKey and secretKey
- When a user creates a bucket, a policy is set on that bucket allowing only their access key
- Users can only access their own buckets
The API returns consistent error responses:
{
"success": false,
"error": "Error description",
"message": "Detailed error message"
}Common HTTP status codes:
200- Success201- Created400- Bad Request (validation errors)401- Unauthorized (invalid/missing token)404- Not Found409- Conflict (resource already exists)500- Internal Server Error
npm start- Start the server in production modenpm run dev- Start the server in development mode with auto-reloadnpm run db:push- Push Prisma schema to databasenpm run db:generate- Generate Prisma client
- User Isolation: Each user can only access their own buckets
- MinIO Bucket Policy Enforcement: Each bucket is protected by a policy allowing only the owner's access key
- JWT Authentication: Secure token-based authentication
- Database Integration: PostgreSQL with Prisma ORM
- Input Validation: Comprehensive validation using express-validator
- Environment Variables: Never commit sensitive information to version control
- Password Hashing: Passwords are hashed using bcrypt
- JWT Security: Use strong JWT secrets in production
- Input Validation: All inputs are validated
- CORS: Configure CORS settings for production use
- MinIO Policies: Users can only access their own buckets
- Set
NODE_ENV=production - Use strong JWT secrets
- Configure SSL/TLS for MinIO
- Set up proper logging
- Implement rate limiting
- Use environment-specific configuration
- Secure database connections
- Ensure MinIO is running:
docker-compose ps - Check MinIO logs:
docker-compose logs minio - Verify MinIO client configuration:
mc admin info local - Check environment variables in
.envfile
- Ensure PostgreSQL is running:
docker-compose ps - Check database logs:
docker-compose logs postgres - Run Prisma commands:
npx prisma db push
- Verify JWT token format
- Check token expiration
- Ensure user exists in database
User already exists: Email is already registeredBucket name already taken: Choose a different bucket nameInvalid credentials: Check email and passwordAccess token required: Include Authorization header
ISC License