2

I'm developing a web site for provide a video on demand service by using React and AWS S3.
I need to must authorize to watch videos.
So I consider to use signed cookie when requesting.

To request using curl was successful.

curl -H 'Cookie:CloudFront-Policy=eyJTd*******************;CloudFront-Signature=b8wt************************************; CloudFront-Key-Pair-Id=AP**********' http://*********.cloudfront.net/hogehoge.m3u8

But I can't get file at React.
My code is there.

export function Movie(){
    document.cookie = `CloudFront-Key-Pair-Id=${"AP**************"}; `
    document.cookie = `CloudFront-Policy=${"eyJT*****************"}; `
    document.cookie = `CloudFront-Signature=${"b8wt****************"}; `

    <ReactPlayer
        url={"http://******.cloudfront.net/hogehoge.m3u8"}
        controls
        config={{
            file: {
                hlsOptions: { 
                xhrSetup: function(xhr: any, url: any) {
                    xhr.withCredentials = true // send cookies
                }
                }
            }
        }}
    >
}

Error message on Chrome(Image)

Request URL: http://*****.cloudfront.net/hogehoge.m3u8
Referrer Policy: strict-origin-when-cross-origin
Connection: keep-alive
Content-Length: 146
Content-Type: text/xml
Date: Tue, 27 Oct 2020 05:54:03 GMT
Server: CloudFront
Via: 1.1 *********.cloudfront.net (CloudFront)
X-Amz-Cf-Id: *******
X-Amz-Cf-Pop: NRT12-C3
X-Cache: Error from cloudfront
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: ja-JP,ja;q=0.9,en-JP;q=0.8,en;q=0.7,en-US;q=0.6
Connection: keep-alive
DNT: 1
Host: ********.cloudfront.net
Origin: http://localhost:3000
Referer: http://localhost:3000/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36

The request looks like not including cookies.
How can I resolve the issue?

twatanbe
  • 23
  • 1
  • 3

1 Answers1

2

Clearly, one of the issues is CORS policy enforcement. If you look at the response, you can see that the host/referrer (i.e. localhost:3000) is different from the target (OP has redacted but let's assume it to be blah.cloudfront.net). Even after addressing CORS, you need to make sure that Cloudfront and S3 are properly set up. I am laying out what worked for me:

  1. Assign custom domain to cloudfront such that the custom domain is a subdomain from where your app's frontend will run. In OP's case, he is using localhost:3000; most probably he is testing on his dev setup, but he must deploy this app at some domain: let's call this 'myapp.com'. So, he can assign a custom domain, say cdn.myapp.com to point to blah.cloudfront.net. You will need to create/import custom SSL certificate for the new custom domain; default cloudfront certificate won't work.enter image description here Refer to this: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html[![enter image description here]2]2 The first one is having no custom domain, hence an empty CNAMEs column. The second one is having a custom domain, hence we have that one printed over there. You can verify that your custom domain got pointed to the cloudfront distribution this way.
  2. Cloudfront behaviour: I am assuming you have already set up trusted key group as at this point, you already have the signed cookie with you. HOWEVER, You will need to create custom Cache Policy and Origin Request Policy. enter image description here See the following screenshots of the custom Cache Policy:enter image description hereand Origin Request Policy:enter image description here The thing to notice is that you will need to whitelist these Headers: Origin, Access-Control-Request-Method, Access-Control-Allow-Origin, Access-Control-Request-Headers. (You might notice that Access-Control-Allow-Origin is not in the dropdown; just go ahead and type it!). Also, allow all cookies.
  3. S3 CORS configuration: Go to the S3 bucket and click on the permissions tab. Scroll down to the CORS configuration. Disclaimer: I just pasted what worked for me. The rationale behind this was that this S3 was going to be accessed by either CDN or app in my scenario. I tried putting '*' being lenient, but CORS policy on Chrome complained that I cannot use a wildcard entry in AllowedOrigins!
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT",
            "POST",
            "GET",
            "HEAD",
            "DELETE"
        ],
        "AllowedOrigins": [
            "cdn.myapp.com",
            "myapp.com",
            "https://cdn.myapp.com",
            "https://myapp.com"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]
  1. react-player: I am using react-player like this (note forceHLS option being set, but it is again specific to my use case. I think this is not mandatory in general)
<ReactPlayer
    className="react-player"
    url={url}
    controls={controls}
    light={light}
    config={
      {
        file: {
          forceHLS: true,
          hlsOptions: {
            xhrSetup: function (xhr, url) {
              xhr.withCredentials = true; // send cookies
            },
          },
        },
      }
    }
    playIcon={<PlayIcon />}
    width="100%"
    height="100%"
  />
Ankit Shubham
  • 2,989
  • 2
  • 36
  • 61