Search code examples
aws-sdk-js

JS AWS S3 SDK getSignedURL returning nothing


I'm new to the AWS SDK and I'm trying to retrieve a presiggned URL for a private object in S3.

I am finding that my promise is resolving with a value of undefined. I suspect that my awsBucket variable is not leveraging my awsConfig but I'm not sure how to get the two to communicate.

My goal is to click a button that updates the src of my img to display an image that is stored in S3. Any help is greatly appreciated.

Below is my code, where you can assume the secret/access keys are populated correctly.

HTML:

<html>

  <head>
    <script type="text/javascript" src="lib/jquery/dist/jquery.min.js"></script>
    <script type="text/javascript" src="lib/bootstrap/dist/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="js/tableau.extensions.1.latest.js"></script>
    <script type="text/javascript" src="js/index.js"></script>

    <!-- AWS SDK-->
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.910.0.min.js"></script>
    
    <link rel="stylesheet" type="text/css" href="lib/bootstrap/dist/css/bootstrap.min.css">

    <!-- Font awesome icons-->
    <script src="https://kit.fontawesome.com/d8651426bf.js" crossorigin="anonymous"></script>

    <title>Image from S3</title>

  </head>

  <body>

    <div class="" id="divMain">
      <p>
        <button id="refreshImageButton" class="btn btn-secondary">
            <i class="fa fa-repeat"></i>
        </button>
      </p>
      <img
        id="displayImage"
        src=""
        alt="Placeholder"
      >
    </div>

  </body>

</html>

JS:


var awsAccessKeyID = 'my-access-key';
var awsSecretAccessKey = 'my-secret-key';
var awsBucketName = 'bucket-name';
const URL_EXPIRATION_TIME = 60; // in seconds

var awsRegion = 'eu-west-2'; // Is this the right way to write the AWS Region?

$(document).ready(initialise());

// This function is called when the page first loads
function initialise() {

    console.log('Test')
    // Refresh image button
    $("#refreshImageButton").click(function() {

      let imagePath='1.jpg'
      refreshImage(imagePath);
    });
  }, function () { console.log('Error while Initializing: ' + err.toString()); });
}

// This function refreshes the image using an incoming path from the data
function refreshImage(imagePath){
  console.log(`Image path: ${imagePath}`)

  let preSignedURL = generatePreSignedGetUrl(imagePath, 'jpg')

  console.log(preSignedURL)
  $("#displayImage").attr("src",preSignedURL);

}

//  This function generated the pre signed URL that can access a private object in S3
function generatePreSignedGetUrl( fileName , fileType) {
  return new Promise(function(resolve, reject){
    let awsConfig = new AWS.Config();
    awsConfig.update({
      accessKeyId: awsAccessKeyID,
      secretAccessKey: awsSecretAccessKey,
    })

    let awsBucket = new AWS.S3();
    let awsBucket = new AWS.S3({
      params: { Bucket: awsBucketName},
      region: awsRegion,
    })

    awsBucket.getSignedUrl('getObject', {
      Key: fileName,
      ContentType: fileType,
      Expires: URL_EXPIRATION_TIME
    } , (err , url) => {
      resolve(url) // API Response Here
    });
  })
};

Solution

  • In the end, I abandoned this approach in favour of a NodeJS backend. Here is my complete and working code:

    
    // Use modules
    const config = require('./config');
    
    const AWS = require('aws-sdk');
    AWS.config.update({
      accessKeyId: config.awsAccessKeyID
      , secretAccessKey: config.awsSecretAccessKey
      , region: config.awsRegion
    });
    
    const s3 = new AWS.S3({signatureVersion: 'v4'});
    
    // Create the parameters for calling listObjects
    var bucketParams = {
      Bucket : 'BUCKETNAME',
    };
    
    // Call S3 to obtain a list of the objects in the bucket
    // This is a good way to test the authentication is working
    s3.listObjects(bucketParams, function(err, data) {
      if (err) {
        console.log("Error", err);
      } else {
        console.log("Success", data);
      }
    });
    
    
    var awsGeneratePresignedURLsBackend = function(app) {
    
      // Enable CORS
      app.use(function (req, res, next) {
          res.header("Access-Control-Allow-Origin", "*");
          res.header("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
          next();
      });
    
      // Connection Test
      app.get('/ConnectionTest', function (req, res) {
          res.send('Connected');
      });
    
      // Slack App Connection Test
      app.post('/generatePreSignedGetUrl', function (req, res) {
          console.log("")
          console.log("--------------------------")
          console.log(`endpoint: generatePreSignedGetUrl`)
          console.log(`type: POST`)
          console.log(`statusCode: ${res.statusCode}`)
    
          const myBucket = req.body.awsBucketName
          const myKey = req.body.fileName
    
          console.log(`Bucket: ${myBucket}`);
          console.log(`Key: ${myKey}`);
    
          const url = s3.getSignedUrl('getObject', {
            Bucket: myBucket,
            Key: myKey
          });
    
          res.send(url)
          console.log(`url: ${url}`)
    
          res.end()
      });
    }
    
    module.exports = awsGeneratePresignedURLsBackend;