• <1 minute

How to make Token authorized AES encrypted HLS stream working in Safari

Azure Media Services provides capability for customers to generate an AES encrypted HLS stream with Token authorization configured on the AES key retrieval.

Azure Media Services provides capability for customers to generate an AES encrypted HLS stream with Token authorization configured on the AES key retrieval. However, as we know, Safari handles HLS playlist and key retrieval within the native stack and there is no easy way for developers to intercept the key request and add in Token into the 2nd level HLS Playlist. Here is a proposed solution if you do some magic on your authentication module to make this work. Below is an diagram to illustrate how this solution works:

Explanation for each step:

1. Customer sends request to your authentication system with video ID. it is important that you have some mapping between video ID and the actual streaming URL. 2. Your authentication system will authenticate user, and request top Playlist from Azure Media Services with video streaming URL. Let’s say the streaming URL looks like this: (format=m3u8-aapl). 3. Azure Media Services will return the top Playlist to the Authentication system. The top playlist looks like this:

#EXTM3U 
#EXT-X-VERSION:4 
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="AAC_und_ch2_96kbps",URI="QualityLevels(92405)/Manifest(AAC_und_ch2_96kbps,format=m3u8-aapl)" 
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="AAC_und_ch2_56kbps",DEFAULT=YES,URI="QualityLevels(53017)/Manifest(AAC_und_ch2_56kbps,format=m3u8-aapl)"
#EXT-X-STREAM-INF:BANDWIDTH=1092766,RESOLUTION=384x288,CODECS="avc1.4d4015,mp4a.40.2",AUDIO="audio"
QualityLevels(960870)/Manifest(video,format=m3u8-aapl)
#EXT-X-STREAM-INF:BANDWIDTH=1607960,RESOLUTION=480x360,CODECS="avc1.4d401e,mp4a.40.2",AUDIO="audio"
QualityLevels(1464974)/Manifest(video,format=m3u8-aapl)
#EXT-X-STREAM-INF:BANDWIDTH=62343,CODECS="mp4a.40.2",AUDIO="audio"
QualityLevels(53017)/Manifest(AAC_und_ch2_56kbps,format=m3u8-aapl) 

4. Modify the top playlist, so the player (Safari in this case) will ping proxy server instead of our key services directly, and add token into the playlist. The authentication system has the knowledge of the how to compose the token but proxy server doesn’t. Here is the way how top playlist is modified:

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="AAC_und_ch2_56kbps",URI="https://test.cloudvideo.azure-int.net/api/ManifestProxy?playbackUrl=(53017)/Manifest(AAC_und_ch2_56kbps,format=m3u8-aapl)&token=[PUT_YOUR_TOKEN_HERE]"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="AAC_und_ch2_96kbps",DEFAULT=YES,URI="https://proxy.cloudvideo.azure-int.net/api/ManifestProxy?playbackUrl=(92405)/Manifest(AAC_und_ch2_96kbps,format=m3u8-aapl)&token=[PUT_YOUR_TOKEN_HERE]"
#EXT-X-STREAM-INF:BANDWIDTH=1092766,RESOLUTION=384x288,CODECS="avc1.4d4015,mp4a.40.2",AUDIO="audio"
https://proxy.cloudvideo.azure-int.net/api/ManifestProxy?playbackUrl=(960870)/Manifest(video,format=m3u8-aapl)&token=[PUT_YOUR_TOKEN_HERE]
#EXT-X-STREAM-INF:BANDWIDTH=1607960,RESOLUTION=480x360,CODECS="avc1.4d401e,mp4a.40.2",AUDIO="audio"
https://proxy.cloudvideo.azure-int.net/api/ManifestProxy?playbackUrl=(1464974)/Manifest(video,format=m3u8-aapl)&token=[PUT_YOUR_TOKEN_HERE]

In the example above, you need to put in an absolute path in URI (otherwise, the request will come back Auth server):

  • https://test.cloudvideo.azure-int.net/api/ManifestProxy? is the address for your proxy server and ManifestProxy is just a parameter for your to parse the URI later
  • PlaybackURL is the actual streaming URL (however, the URL now is the 2nd level manifest with quality level appends
  • Token is appended at the end as a parameter. Our key services accept token as parameter in the key request

5. Safari now will send  request based on the URL provided in URI parameter to retrieve 2nd level playlist which contains the key information. Since we changed the playlist to point to our proxy server, the request will come to proxy server 6. Our proxy server will receive the 2nd level playlist request. Remove https://test.cloudvideo.azure-int.net/api/ManifestProxy? and ping origin server with the playbackUrl in the playlist to get 2nd playlist with actual key URL in it. And append the token within this 2nd level Playlist. So the returned playlist looks like this:

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:10
#EXT-X-KEY:METHOD=AES-128,URI="https://test.keydelivery.mediaservices.windows.net/?kid=a99263cd-43b3-490a-a4d6-ea04d4645fb7&token=[PUT_YOUR_Token]
#EXT-X-PROGRAM-DATE-TIME:1970-01-01T00:00:00Z
#EXTINF:3.947392,no-desc
(92405)/Fragments(AAC_und_ch2_96kbps=0,format=m3u8-aapl)
#EXT-X-ENDLIST

7. Safari now will send a key request with the URI after #EXT-X-KEY:METHOD=AES-128,URI= to our key server. Since a token is embedded as a parameter, our key service could authorize the request and give player the AES key. We've made this work by uploading code we used to modify the playlist on proxy server here, and you can see a working sample site here. Please feel free to reach out if you have any questions!