How to use hls with private videos in native suported browser that does not support mediaSource?

Hi I implemented private video using hls with hls.js and it works , I get the X-Token on the first request and add it to the xhr config on the follow up request. The part I can’t seem to get a solution for is when you want to use native support for hls , like for instance on an iphone then it does not support the mediaSource extension. So I can’t set a config to change the follow up headers to include the X-Token.

So my question is how can I add a custom header to the request the

if (Hls.isSupported()) {
    fetch(response?.result?.hls, { credentials: 'include' }).then((res) => {
    xtoken = res.headers.get('X-Token-Session');
    let hls = new Hls();
    hls.loadSource(response?.result?.hls);
    hls.attachMedia(this.video);
    this.video.pause();
    this.video.currentTime = 0;
    });
} else {
    fetch(response?.result?.hls, { credentials: 'include' }).then((res) => {
    xtoken = res.headers.get('X-Token-Session');
    this.video.src = response?.result?.hls;
    this.video.pause();
    this.video.currentTime = 0;
    this.setVideoHeight(this.video);
});

Any ideas are welcome, Thanks

1 Like

I’m curious to hear more about this as well.

How does the api.video player play private videos on iOS?

I also can’t get private videos to play on iOS using VideoJS and by setting the X-Token-Session as described in Blog | Inserting custom headers.

See my Flask/jQuery/VideoJS implementation below.

        let manifestUrl;

        $.get('{{ url_for('video_view.get_video', video_id=video_id) }}')
            .then((data) => {
                manifestUrl = data.assets.hls;
                return $.get(manifestUrl)
            })
            .then((data, status, request) => {
                videojs.options.vhs.overrideNative = true;
                videojs.Vhs.xhr.beforeRequest = (options) => {
                    options.headers = {
                        ...options.headers,
                        "X-Token-Session": request.getResponseHeader('x-token-session')
                    };

                    return options;
                };
            })
            .then(() => {
                let player = videojs('my-video');

                player.ready(() => {
                    player.controls();
                    player.src({
                        src: manifestUrl,
                        {#src: 'https://cdn.api.video/vod/vi4blUQJFrYWbaG44NChkH27/hls/manifest.m3u8',#}
                        type: 'application/x-mpegURL'
                    });
                });
            })

I get a 404 error which I’ve discovered means that the X-Token-Session header is not set. After doing a bunch of research I learned that VideoJS uses Safari’s native HLS implementation.

This can be bypassed on macOS by setting videojs.options.vhs.overrideNative = true; which in turn sets videojs.Vhs.xhr.beforeRequest.

This is, however, not supported on iOS as there’s only partial support for MediaSource which in turn means that videojs.Vhs.xhr.beforeRequest is not called and the header is not set.

How can we set the header in Safari on iOS? How does the video.api player do it?

Hi Simeon, we found this post, in the comments it explain you can use a query param for the token. We’re going to try that approach.

1 Like

Thanks for the heads up! I saw that thread but missed the query parameter part. I’ll give it a go as well!

@rudolph Did you manage to make it work?

The example JSFiddle you point to also uses videojs.Vhs.xhr.beforeRequest which does not work on iOS.

I was hoping I could just append the session token to the manifest URL like so

let player = videojs('my-video');

player.ready(() => {
    player.controls();
    player.src({
        src: manifestUrl + '?avh=' + sessionToken,
        type: 'application/x-mpegURL'
});

but that unfortunately does nothing as the query parameter seems to be ignored.

Unfortunately the only way to make private videos work on IOS is to use a service worker.
We have just uploaded a small sample application showing how it is possible to do this.

The application is here: https://apivideo-private-videos.herokuapp.com/
The source code is here: GitHub - apivideo/private-videos-with-custom-player-sample: Demonstrate how to display private videos using a third-party player

On IOS devices, the api.video player uses a service worker similar to this one for playing private videos.