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.
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
- Client requests an upload slot from your NestJS API with file metadata.
- API validates auth, tenant scope, and MIME allowlists.
- Server returns a short-TTL presigned
PUTURL scoped to a single object key. - 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.