<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Fuongz's Blog]]></title><description><![CDATA[Fuongz's Blog]]></description><link>https://blog.phuongphung.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Apr 2026 11:22:07 GMT</lastBuildDate><atom:link href="https://blog.phuongphung.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Securely Upload Files to S3 for Guests Using AWS Cognito]]></title><description><![CDATA[For security reasons, if you allow guest users to upload files from your app, it's better to use Guest Access from AWS Cognito instead of a direct AWS Access Key from an IAM User.
Why?

An IAM User access key is long-lived and never expires.

With AW...]]></description><link>https://blog.phuongphung.com/aws-amplify-deploy-permissions</link><guid isPermaLink="true">https://blog.phuongphung.com/aws-amplify-deploy-permissions</guid><category><![CDATA[AWS]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Amazon S3]]></category><category><![CDATA[Amazon Cognito]]></category><dc:creator><![CDATA[Phuong Phung]]></dc:creator><pubDate>Fri, 30 Jan 2026 05:07:59 GMT</pubDate><content:encoded><![CDATA[<p>For security reasons, if you allow guest users to upload files from your app, it's better to use Guest Access from AWS Cognito instead of a direct AWS Access Key from an IAM User.</p>
<h3 id="heading-why"><strong>Why?</strong></h3>
<ul>
<li><p>An IAM User access key is long-lived and never expires.</p>
</li>
<li><p>With AWS Cognito, you can decide how long the temporary guest access key will be valid.</p>
</li>
</ul>
<h3 id="heading-requirements"><strong>Requirements:</strong></h3>
<ul>
<li><p><strong>AWS Cognito &gt; Identity pool</strong></p>
</li>
<li><p><strong>S3 Bucket</strong></p>
</li>
</ul>
<h3 id="heading-step-by-steps"><strong>Step-by-steps:</strong></h3>
<ol>
<li><p><strong>Create Cognito Identity Pool</strong></p>
<ol>
<li><p>Go to <strong>Amazon Cognito</strong> &gt; <strong>Identity pools</strong> &gt; <strong>Create identity pool</strong></p>
</li>
<li><p>Configure identity pool trust:</p>
</li>
</ol>
</li>
</ol>
<ul>
<li><p>Select: <strong>Guest access</strong> (this enables <strong>unauthenticated</strong>)</p>
</li>
<li><p>Click <strong>Next</strong></p>
</li>
</ul>
<ol start="3">
<li>Configure permissions:</li>
</ol>
<ul>
<li><p>Select: <strong>Create a new IAM role</strong> (Your AWS IAM account needs some permissions to do that)</p>
<ul>
<li><p><code>iam:CreateRole</code> (create role)</p>
</li>
<li><p><code>iam:PutRolePolicy</code> (add inline policies)</p>
</li>
<li><p><code>iam:AttachRolePolicy</code> (attach managed policies)</p>
</li>
<li><p><code>iam:DetachRolePolicy</code> (detach managed policies)</p>
</li>
<li><p><code>iam:TagRole</code> / <code>iam:UntagRole</code> (if you use tags)</p>
</li>
</ul>
</li>
<li><p>Role name: <strong>guest-uploader-role</strong> or anything you want</p>
</li>
<li><p>Click <strong>Next</strong></p>
</li>
</ul>
<ol start="4">
<li>Configure properties:</li>
</ol>
<ul>
<li><p>Identity pool name: <strong>guest-uploader-pool</strong> or anything you want</p>
</li>
<li><p>Click <strong>Next</strong></p>
</li>
<li><p>Review and create &gt; Click <strong>Create identity pool</strong></p>
</li>
</ul>
<ol start="2">
<li><p><strong>Create S3 Bucket</strong></p>
<ol>
<li><p>Go to <strong>S3</strong> &gt; Click on the button <strong>Create bucket</strong></p>
</li>
<li><p>Fill-out your bucket data (eg. bucket name as <strong>guest-bucket</strong>)</p>
</li>
<li><p>Click <strong>Create Bucket</strong></p>
</li>
</ol>
</li>
<li><p><strong>Add S3 Permission to the Role</strong></p>
<ol>
<li><p>Go to <strong>IAM</strong> &gt; <strong>Roles</strong> &gt; search for <strong>guest-uploader-role</strong> (you created on the previous step)</p>
</li>
<li><p>Click the role &gt; <strong>Add permissions</strong> &gt; <strong>Create inline policy</strong></p>
</li>
<li><p>Switch to JSON tab, paste:</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
   <span class="hljs-attr">"Statement"</span>: [{
     <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
     <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:PutObject"</span>,
     <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::guest-bucket/uploads/*"</span>
   }]
 }
</code></pre>
<ul>
<li><strong>Note</strong>: Because I want to store all guest upload files in the <code>/uploads</code> folder, I put it in the source field.</li>
</ul>
</li>
<li><p>Click <strong>Next</strong> &gt; Name it <strong>S3UploadPolicy</strong> &gt; <strong>Create policy</strong></p>
</li>
</ol>
</li>
<li><p><strong>Update CORS for S3 bucket to allow your frontend to put file</strong>:</p>
<ol>
<li><p>Go to <strong>S3</strong> &gt; Click on bucket <strong>guest-bucket</strong> or anything you created from previous step</p>
</li>
<li><p>Go to <strong>Permissions</strong> tab &gt; Scroll down to <strong>Cross-origin resource sharing (CORS)</strong> (bottom of page)</p>
</li>
<li><p>Click on <strong>Edit</strong>, paste:</p>
<pre><code class="lang-json"> [
     {
         <span class="hljs-attr">"AllowedHeaders"</span>: [
             <span class="hljs-string">"*"</span>
         ],
         <span class="hljs-attr">"AllowedMethods"</span>: [
             <span class="hljs-string">"PUT"</span>
         ],
         <span class="hljs-attr">"AllowedOrigins"</span>: [
             <span class="hljs-string">"[YOUR_FRONTEND_URL]"</span>,
         ],
         <span class="hljs-attr">"ExposeHeaders"</span>: []
     }
 ]
</code></pre>
<ol start="4">
<li>Click on <strong>Save Changes</strong></li>
</ol>
</li>
</ol>
</li>
</ol>
<p><strong>Best Practices:</strong></p>
<ol>
<li><p>For security reasons, it is advisable to <strong>block all public access</strong> to the S3 bucket.</p>
</li>
<li><p>To optimize costs, consider setting a <strong>lifecycle policy</strong> for the bucket, such as deleting files after 6 months if they are not important.</p>
</li>
</ol>
]]></content:encoded></item></channel></rss>