S3 Presigned URLs - Build One-Time Download Links
Problem
Need to provide file download links, but unlimited downloads by anyone is not acceptable. Both time limits and download count limits are required.
Solution
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const s3 = new S3Client({ region: 'ap-northeast-2' });
async function generateDownloadUrl(bucket: string, key: string) {
const command = new GetObjectCommand({ Bucket: bucket, Key: key });
const url = await getSignedUrl(s3, command, {
expiresIn: 300, // 5 minutes
});
return url;
}
// Store token in DynamoDB (1-hour TTL, max 1 download)
const token = crypto.randomUUID();
await docClient.send(new PutCommand({
TableName: 'download-tokens',
Item: {
PK: `TOKEN#${token}`,
downloadCount: 0,
maxDownloads: 1,
ttl: Math.floor(Date.now() / 1000) + 3600,
},
}));
Key Points
- Presigned URLs embed signing info in the URL, enabling direct download without AWS credentials. After expiration, requests return 403.
- DynamoDB TTL auto-deletes expired tokens. No cron jobs needed for cleanup.
expiresIncontrols the URL’s validity; DynamoDB TTL controls the token’s validity. Separating these provides more flexibility.