S3 upload directly in JavaScript

3.6k views Asked by At

I'm trying to accomplish the simple, and upload to Amazon S3 directly JavaScript. How and where would I hide my access and secret keys though? I'm not seeing anything in their documentation or on this site that answers this.

I'm using their recommended way to set this up in HTML. I'm also using Backbone and Bower.

<script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.25.min.js"></script>
<script type="text/javascript">
  // See the Configuring section to configure credentials in the SDK
  AWS.config.credentials = ...;

  // Configure your region
  AWS.config.region = 'us-west-2';
</script>
<input type="file" id="file-chooser" /> 
<button id="upload-button">Upload to S3</button>
<div id="results"></div>

<script type="text/javascript">
  var bucket = new AWS.S3({params: {Bucket: 'myBucket'}});

  var fileChooser = document.getElementById('file-chooser');
  var button = document.getElementById('upload-button');
  var results = document.getElementById('results');
  button.addEventListener('click', function() {
    var file = fileChooser.files[0];
    if (file) {
      results.innerHTML = '';

      var params = {Key: file.name, ContentType: file.type, Body: file};
      bucket.putObject(params, function (err, data) {
        results.innerHTML = err ? 'ERROR!' : 'UPLOADED.';
      });
    } else {
      results.innerHTML = 'Nothing to upload.';
    }
  }, false);
</script>
2

There are 2 answers

0
peter-b On

You can't hide your credentials in the javascript, as all the code is sent to the client and therefore visible. There are a number of things you could do to work around this though:

  • If the users of your application are trusted and authenticated, you can choose only to serve the script to authenticated users by checking cookies in something like PHP at the top of the file, and setting up your server appropriately to allow this.
  • Alternatively, if the users of your script are untrusted, I would recommend you send requests to your server, rather than S3 directly. Your server can then authenticate and handle the transfer of the file as a proxy, without the key ever being publicly-visible.
0
chrisboustead On

You can use STS to generate short lived temporary credentials for each upload, and pass those to the JS SDK so that you never have to reveal your long term API keys.

Example using AWS PHP SDK (composer package: "aws/aws-sdk-php":"~2.4"), assumes your access_key_id and secret_access_key are available in the ENV.

Sloppy example:

<?php 
include 'vendor/autoload.php';

use Aws\Sts\StsClient;

/** Create Temporary Credentials */
$stsclient = StsClient::factory();
$temp_creds = $stsclient->getSessionToken(900)->get('Credentials'); // 15 minute expiration

?>
<script>
AWS.config.credentials = {
    accessKeyId : '<?php echo $temp_creds['AccessKeyId']; ?>',
    secretAccessKey : '<?php echo $temp_creds['SecretAccessKey']; ?>',
    sessionToken : '<?php echo $temp_creds['SessionToken']; ?>'
};
AWS.config.region = 'your-region';
</script>

This way you never have to reveal your access access_key_id and secret_access_key. The STS generated keys will be invalidated after the set time interval. Be sure to follow best practices, like creating a limited-role IAM user for the long-term stored credentials.

Reference: http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.Sts.StsClient.html#_getSessionToken