DEV Community

Cover image for Uploading Files Securely to AWS S3 Using Presigned URLs
HexShift
HexShift

Posted on

2

Uploading Files Securely to AWS S3 Using Presigned URLs

Uploading Files Securely to AWS S3 Using Presigned URLs

Subtitle: A practical guide to keeping your uploads safe by generating and using AWS presigned URLs in your web applications.

Uploading files directly to AWS S3 from a frontend app can be risky if not handled securely. Exposing your S3 credentials or allowing open write access is a big no-no. The best practice? Use presigned URLs — short-lived links that grant temporary access to upload a specific file.

In this tutorial, you'll learn how to securely generate and use presigned URLs for file uploads using Node.js and AWS SDK v3.

Step 1: Set Up Your AWS S3 Bucket

In the AWS Console:

  • Create an S3 bucket (or use an existing one).
  • Ensure it has private access by default.
  • Enable CORS (Cross-Origin Resource Sharing) to allow browser-based uploads. Example configuration:
{
  "CORSRules": [
    {
      "AllowedHeaders": ["*"],
      "AllowedMethods": ["PUT"],
      "AllowedOrigins": ["*"],
      "ExposeHeaders": []
    }
  ]
}

Step 2: Install the AWS SDK

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

Step 3: Generate the Presigned URL in Your Backend

Create an endpoint that your frontend can call to get a temporary upload URL.

// server.js (Node.js/Express)

import express from 'express';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const app = express();
const s3 = new S3Client({ region: 'your-region' });

app.get('/generate-presigned-url', async (req, res) => {
  const { fileName, fileType } = req.query;

  const command = new PutObjectCommand({
    Bucket: 'your-bucket-name',
    Key: fileName,
    ContentType: fileType
  });

  const url = await getSignedUrl(s3, command, { expiresIn: 60 }); // 1 minute

  res.json({ url });
});

app.listen(3000, () => console.log('Server running on port 3000'));

Step 4: Upload the File in Your Frontend

// JavaScript (frontend)

async function uploadFile(file) {
  const res = await fetch(`/generate-presigned-url?fileName=${file.name}&fileType=${file.type}`);
  const { url } = await res.json();

  await fetch(url, {
    method: 'PUT',
    headers: {
      'Content-Type': file.type
    },
    body: file
  });

  alert('Upload complete!');
}

Conclusion

Presigned URLs are a secure and scalable solution for file uploads in modern web apps. By delegating the responsibility to AWS, you minimize backend load and eliminate security risks associated with direct uploads. Make sure to apply appropriate file type and size validations before generating URLs!

🚀 Want more tutorials like this? Consider supporting my writing:

☕ Support me on Buy Me a Coffee

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo 📊✨

Top comments (0)

Jetbrains Survey

Calling all developers!

Participate in the Developer Ecosystem Survey 2025 and get the chance to win a MacBook Pro, an iPhone 16, or other exciting prizes. Contribute to our research on the development landscape.

Take the survey