Back to Insights
Cloud Architecture

Securing Cloud Infrastructure: Implementing Direct-to-S3 Presigned URL Components in NestJS

Bypass server upload bottlenecks with signed storage policies, Helmet.js hardening, and defense-in-depth API security.

6 min read

Routing file uploads through application servers is an architectural anti-pattern at scale. Direct-to-S3 presigned URLs shift bandwidth to object storage while your API retains full authorization control.

The presigned URL flow

  1. Client requests an upload slot from your NestJS API with file metadata.
  2. API validates auth, tenant scope, and MIME allowlists.
  3. Server returns a short-TTL presigned PUT URL scoped to a single object key.
  4. Client uploads directly to S3; API receives an event via SQS for post-processing.
@Post('uploads/presign')
@UseGuards(JwtAuthGuard)
async presign(@Body() dto: PresignDto, @User() user: AuthUser) {
  const key = `tenants/${user.tenantId}/${uuid()}`;
  const url = await this.s3.getSignedUrl('putObject', {
    Bucket: process.env.ASSETS_BUCKET,
    Key: key,
    Expires: 300,
    ContentType: dto.mimeType,
  });
  return { url, key };
}

Helmet.js and API hardening

Every NestJS deployment ships with Helmet for security headers, strict CORS origins, and request size limits on metadata endpoints. Upload authorization never trusts client-supplied paths—keys are server-generated exclusively.

CloudFront and IAM least privilege

Delivery uses CloudFront with origin access controls. IAM policies grant the application role s3:PutObject only on tenant prefixes, never bucket-wide wildcards. Access logs feed SIEM pipelines for compliance review.