amazon-cloudfrontvideo.jshls.jsvivado-hls

Unable to play HLS m3u8 file with AWS CloudFront Signed Cookies


I am working on a project where I will need to play HLS encrypted video (.m3u8) file. I am using CloudFront and signed cookies to secure the content. I am able to play .m3u8 file without signed cookies but when I use signed cookies then cookies do not get send in requests.

I am using the alternate domain for CloudFront distribution and I confirm that apart from .m3u8 file I am able to access all other files using signed cookies.

After research, I found that if I set withCredentials to true like the following code then signed cookies will be send in request:

player.ready(function() {
    player.src({
        src: 'https://protected.example.com/output-plain/art.m3u8',
        type: 'application/x-mpegURL',
        withCredentials: true
    });
});

This code works and signed cookies are getting send in request however I started getting a new error which is:

Access to XMLHttpRequest at 'https://protected.example.com/output-plain/art.m3u8undefined' from origin 'https://example.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Then I found that I have to set Access-Control-Allow-Credentials to true. however, this does not work for me.

I am using video.js library, I have also tried hls.js and getting the same error and stuck at same place.

I am stuck on this issue for the last 7 days and I think AWS docs are really overwhelming, I have referred many questions on SO and issues on Github but still no luck. Hope someone will help me here.

Here is the screenshot of CloudFront distribution behavior:

enter image description here enter image description here enter image description here

And here is my php and js code; index.php:

<?php

header("Access-Control-Allow-Origin: https://protected.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");

?>

<!DOCTYPE html>
<html>
<head>
    <link href="https://vjs.zencdn.net/7.10.2/video-js.css" rel="stylesheet" />
</head>


<body>

<video
        id="video_player"
        class="video-js"
        controls
        preload="auto"
        poster="//vjs.zencdn.net/v/oceans.png"
        data-setup='{}'
        width=600 height=300>
      
    </video>

<script src="https://vjs.zencdn.net/7.10.2/video.js"></script>

<script>
    var player = videojs('video_player')

    player.responsive(true);

    player.ready(function() {
        player.src({
            src: 'https://protected.example.com/output-plain/art.m3u8',
            type: 'application/x-mpegURL',
            withCredentials: true
        });
    });
</script>

</body>
</html>

Here is S3 bucked CORS Policy:

[
    {
        "AllowedHeaders": [
            ""
        ],
        "AllowedMethods": [
            "POST",
            "GET",
            "PUT",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]

Thank you in advance.


Solution

  • The answer is within the browser's error message, "The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'." Your S3 bucket's CORS policy cannot use a wildcard for the AllowedOrigins value.

    Also your empty AllowedHeaders value may be removing the Host value from the preflight request check, so let's set it to a wildcard just to be safe.

    If you update your S3 bucket's CORS policy to this, it should resolve the issue:

    [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "POST",
                "GET",
                "PUT",
                "HEAD"
            ],
            "AllowedOrigins": [
                "https://example.com",
                "https://protected.example.com"
            ],
            "ExposeHeaders": []
        }
    ]