Search code examples
node.jsreactjsamazon-s3corscross-origin-resource-policy

cross origin resource policy issue when playing files from s3 on deployed app


I have a deployed app on Heroku that allows me to play audio files. You can check it out here https://telecurve.herokuapp.com/manage. Before I had no issues playing the files in Heroku but after I modified my server.js file (my app is an Express app that is deployed with a built Create React app), I get this error. You can try playing an audio file and seeing the response. However, I am still able to download files from s3 with the download button and have no issues.

Here is some relevant code:

server.js

    require('rootpath')();
    const path = require('path');
    const express = require('express');
    const app = express();
    const bodyParser = require('body-parser');
    const cookieParser = require('cookie-parser');
    const cors = require('cors');
    
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
    app.use(cookieParser());
    
    // Have Node serve the files for our built React app
    app.use(express.static(path.resolve(__dirname, 'build')));
    
    // allow cors requests from any origin and with credentials
    app.use(cors({ origin: (origin, callback) => callback(null, true), credentials: true }));
    
   //change added that caused issues with the playing mechanism. Needed these headers for another 
    app.use(function(req, res, next) {
      res.header("Cross-Origin-Embedder-Policy", "require-corp");
      res.header("Cross-Origin-Opener-Policy", "same-origin");
      next();
    });
    
    
    // file api routes
    app.use('/accounts', require('./accounts/accounts.controller'));
    
    
    // All other GET requests not handled before will return our React app
    app.get('*', (req, res) => {
        res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
    });
    
    app.get('/app', async (req, res) => {
      res.sendFile(path.join(__dirname, 'public/index.html'));
    });
    // does work, cors headers in response as expected
    
    
    // start server
    const port = process.env.PORT || 2000;
    app.listen(port, () => console.log('Server listening on port ' + port));

this is the particular change in server.js that I added:

   //change added that caused issues with the playing mechanism. Needed these headers for another 
    app.use(function(req, res, next) {
      res.header("Cross-Origin-Embedder-Policy", "require-corp");
      res.header("Cross-Origin-Opener-Policy", "same-origin");
      next();
    });

Maybe I need to add an additional header for s3?

I also recently removed this code:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

Here is my presigning method in the backend that I use to generate urls to play/download from:

  const customer_id = data['customer-id'];
  const sound_id = data['sound-id'];
  
  return new Promise((resolve, reject) => {
    //get presigned url

    var myBucket = process.env.NODE_APP_BUCKET_NAME;
    var myKey = "sounds/" + customer_id + "/" + sound_id + ".wav"; 
    const signedUrlExpireSeconds = 120;
    try {
      const url = s3.getSignedUrl('getObject', {
        Bucket: myBucket,
        Key: myKey,
        ResponseContentDisposition: 'attachment',
        Expires: signedUrlExpireSeconds
      });
      resolve(url)
    }
    catch {
      console.log('S3 Object does not exist');
      resolve('');
    }
  });

I then take this url, create a new audio object with var audio = new Audio(url) and play it.

Let me know if you see anything going wrong or if im missing anything.


Solution

  • You seem to directly use the URL pointing at your audio file on S3, meaning that:

    Your app was down when I wrote this, so I couldn't actually validate it's caused by S3 cross-origin resources, but based on your question, it is the most likely issue.