A web application that allows users to upload, view, download, and delete files stored securely in AWS S3.
This repository contains two implementations of the same application:
- python-version/ — Python Flask backend, plain HTML/JS frontend
- ts-version/ — Node.js + Express backend (TypeScript), React frontend (TypeScript + Vite)
Both versions use the same AWS S3 bucket and IAM configuration. The documentation below applies to both.
The frontend is a simple HTML/JS page that runs in the browser. When a user uploads a file, the browser sends it to the Python Flask API, which validates it and stores it in an AWS S3 bucket. When the page loads, the frontend makes a GET request to the API to retrieve the list of files stored in S3 and displays them. Users can also delete files, which sends a DELETE request to the API, which removes the file from the S3 bucket. Downloads work via a pre-signed URL generated by the API, which gives the browser temporary access to the file directly from S3.
S3 - Used to store uploaded files in the cloud. The bucket is configured as private with no public access, and server-side encryption (SSE-S3) is enabled so all files are encrypted at rest. Files are organised under an uploads/ prefix within the bucket.
IAM - Used to control access to the S3 bucket. A custom IAM user was created with a least-privilege policy that only grants read, write, list, and delete permissions on this specific bucket. No other AWS services or resources are accessible with these credentials.
Private bucket - Files cannot be viewed by anyone without going through the API. This means access can be controlled per user in future, and no file is ever publicly reachable by URL.
SSE-S3 encryption - All files are encrypted at rest in S3. If someone gained access to the physical storage, the data would be unreadable without the encryption key.
IAM least-privilege - The IAM user only has the permissions the application actually needs. If the credentials were ever compromised, the damage would be limited to this one bucket.
Environment variables - AWS credentials are stored in a .env file and never hardcoded. This means they won't get accidentally committed to a repository, and can be changed without touching the code.
File validation - File type and size are validated on the backend before uploading. Frontend checks can be bypassed by sending requests directly to the API, so backend validation is the only reliable line of defence.
Pre-signed URLs - Downloads use temporary URLs that expire after 5 minutes. The bucket stays fully private and no permanent or shareable link to a file ever exists.
- Clone the repository and navigate to
python-version/ - Create
backend/.envwith your AWS credentials (see Environment Variables below) - Create and activate a virtual environment:
python -m venv venvvenv\Scripts\activate(Windows) orsource venv/bin/activate(Mac/Linux)
- Install dependencies:
pip install flask flask-cors boto3 python-dotenv - Run the backend:
python backend/app.py - Open
frontend/index.htmlin your browser
- Clone the repository and navigate to
ts-version/ - Create
backend/.envwith your AWS credentials (see Environment Variables below) - Install backend dependencies:
cd backend && npm install - Start the backend:
npm run dev - In a new terminal, install frontend dependencies:
cd frontend && npm install - Start the frontend:
npm run dev - Open
http://localhost:5173in your browser
The following environment variables are required in a backend/.env file:
| Variable | Description |
|---|---|
AWS_ACCESS_KEY_ID |
IAM user access key |
AWS_SECRET_ACCESS_KEY |
IAM user secret key |
AWS_REGION |
AWS region where your bucket is hosted |
S3_BUCKET_NAME |
Name of your S3 bucket |
Never commit the .env file to version control.