title: How do I client-side upload a viewable file to Amazon S3?
body: <p>Let me start of by saying that I am normally very reluctant to post this questions as I always feel that there's an answer to everything SOMEWHERE on the internet. After spending countless hours looking for an answer to this question, I've finally given up on this statement however.</p>
  
  <h1>Assumption</h1>
  
  <p>This works:</p>
  
  <pre><code>s3.getSignedUrl('putObject', params);
  </code></pre>
  
  <h1>What am I trying to do?</h1>
  
  <ol>
  <li>Upload a file via PUT (from the client-side) to Amazon S3 using the getSignedUrl method</li>
  <li>Allow anyone to view the file that was uploaded to S3</li>
  </ol>
  
  <p><strong>Note:</strong> If there's an easier way to allow client side (iPhone) uploads to Amazon S3 with pre-signed URLs (and without exposing credentials client-side) I'm all ears.</p>
  
  <h1>Main Problems*</h1>
  
  <ol>
  <li>When viewing the AWS Management Console, the file uploaded has blank Permissions and Metadata set.</li>
  <li>When viewing the uploaded file (i.e. by double clicking the file in AWS Management Console) I get an <code>AccessDenied</code> error.</li>
  </ol>
  
  <h1>What have I tried?</h1>
  
  <h2>Try #1: My original code</h2>
  
  <p>In NodeJS I generate a pre-signed URL like so:</p>
  
  <pre><code>var params = {Bucket: mybucket, Key: "test.jpg", Expires: 600};
  s3.getSignedUrl('putObject', params, function (err, url){
    console.log(url); // this is the pre-signed URL
  });
  </code></pre>
  
  <p>The pre-signed URL looks something like this:</p>
  
  <pre><code>https://mybucket.s3.amazonaws.com/test.jpg?AWSAccessKeyId=AABFBIAWAEAUKAYGAFAA&amp;Expires=1391069292&amp;Signature=u%2BrqUtt3t6BfKHAlbXcZcTJIOWQ%3D
  </code></pre>
  
  <p>Now I upload the file via PUT</p>
  
  <pre><code>curl -v -T myimage.jpg https://mybucket.s3.amazonaws.com/test.jpg?AWSAccessKeyId=AABFBIAWAEAUKAYGAFAA&amp;Expires=1391069292&amp;Signature=u%2BrqUtt3t6BfKHAlbXcZcTJIOWQ%3D
  </code></pre>
  
  <p><strong>PROBLEM</strong>
  <br />
  I get the <strong>*Main Problems</strong> listed above</p>
  
  <h2>Try #2: Adding Content-Type and ACL on PUT</h2>
  
  <p>I've also tried adding the Content-Type and x-amz-acl in my code by replacing the params like so:</p>
  
  <pre><code>var params = {Bucket: mybucket, Key: "test.jpg", Expires: 600, ACL: "public-read-write", ContentType: "image/jpeg"};
  </code></pre>
  
  <p>Then I try a good ol' PUT:</p>
  
  <pre><code>curl -v -H "image/jpeg" -T myimage.jpg https://mybucket.s3.amazonaws.com/test.jpg?AWSAccessKeyId=AABFBIAWAEAUKAYGAFAA&amp;Content-Type=image%2Fjpeg&amp;Expires=1391068501&amp;Signature=0yF%2BmzDhyU3g2hr%2BfIcVSnE22rY%3D&amp;x-amz-acl=public-read-write
  </code></pre>
  
  <p><strong>PROBLEM</strong>
  <br />
  My terminal outputs some errors:</p>
  
  <pre><code>-bash: Content-Type=image%2Fjpeg: command not found
  -bash: x-amz-acl=public-read-write: command not found
  </code></pre>
  
  <p>And I also get the <strong>*Main Problems</strong> listed above.</p>
  
  <h2>Try #3: Modifying Bucket Permissions to be public</h2>
  
  <p>All of the items listed below are ticked in the AWS Management Console)</p>
  
  <pre><code>Grantee: Everyone can [List, Upload/Delete, View Permissions, Edit Permissions]
  Grantee: Authenticated Users can [List, Upload/Delete, View Permissions, Edit Permissions]
  </code></pre>
  
  <h3>Bucket Policy</h3>
  
  <pre><code>{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "Stmt1390381397000",
          "Effect": "Allow",
          "Principal": {
              "AWS": "*"
          },
          "Action": "s3:*",
          "Resource": "arn:aws:s3:::mybucket/*"
      }
  ]
  }
  </code></pre>
  
  <h2>Try #4: Setting IAM permissions</h2>
  
  <p>I set the user policy to be this:</p>
  
  <pre><code>{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": "s3:*",
        "Resource": "*"
      }
    ]
  }
  </code></pre>
  
  <p>AuthenticatedUsers group policy to be this:</p>
  
  <pre><code>{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "Stmt1391063032000",
        "Effect": "Allow",
        "Action": [
          "s3:*"
        ],
        "Resource": [
          "*"
        ]
      }
    ]
  }
  </code></pre>
  
  <h2>Try #5: Setting CORS policy</h2>
  
  <p>I set the CORS policy to this:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"&gt;
      &lt;CORSRule&gt;
          &lt;AllowedOrigin&gt;*&lt;/AllowedOrigin&gt;
          &lt;AllowedMethod&gt;PUT&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;POST&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;DELETE&lt;/AllowedMethod&gt;
          &lt;AllowedMethod&gt;GET&lt;/AllowedMethod&gt;
          &lt;MaxAgeSeconds&gt;3000&lt;/MaxAgeSeconds&gt;
          &lt;AllowedHeader&gt;*&lt;/AllowedHeader&gt;
      &lt;/CORSRule&gt;
  &lt;/CORSConfiguration&gt;
  </code></pre>
  
  <p>And... Now I'm here.</p>