Using AES with token authentication for Media Services
This post is a step by step walkthrough of using the Azure Media Services Explorer (http://aka.ms/amse) to apply AES encryption to a video asset. I’ll describe the full process of applying envelope (AES) encryption and providing a JWT token with claims authentication. Note that while this article specifically discusses AES, some of the same principles apply to other DRM like PlayReady, Widevine, and FairPlay as far as the token authentication goes.
Whenever you’re changing the format of video or encrypting it, the first thing you should understand is what clients support that video format or encryption type. With the Azure Media Player we have a compatibility list available at http://amp.azure.net/libs/amp/latest/docs/index.html#compatibility-matrix. This lists OS and browser combinations and what playback mechanism is supported with unencrypted, envelope (AES), and DRM (PlayReady/Widevine/FairPlay). Since we’re focusing on AES here, the middle column of the compatibility matrix lists what the expected tech is and whether or not the OS/browser combination is supported. For example, with the Edge / IE 11 browsers on Windows 10 the azureHtml5Js tech is used to play AES encrypted content. You can find more about the techs at http://amp.azure.net/libs/amp/latest/docs/index.html#playback-technology-tech-. For modern OS’s and browsers AES is the lowest common denominator for encryption. But keep in mind that iOS 6+ with Safari and Android 4.0 with Chrome 37+ doesn’t support token authentication without a token proxy. We’ll have to go back to the player docs once we have the token so that you know how to pass the token to the Azure Media Player.
Now that we know what browsers are supported you’ll need to encrypt the asset. I’m performing all of the media processing in Azure Media Services Explorer (http://aka.ms/amse). First we’ll upload and encode an asset. I’m encoding the asset with Media Encoder Standard with the Content Adaptive Multiple Bitrate MP4 encoding profile. This allows us to stream the output. To encrypt the asset with AES:
- Right click on the output asset and choose Security / Add dynamic encryption and key delivery policies to the asset(s)…
- For Protection choose Envelope clear key.
- For Delivery I recommend checking Enable dynamic encryption and checking all three delivery protocol boxes (HLS, DASH, Smooth Streaming).
- On the next dialog for AES Key Generation I recommend using Automatic generation (random content key) .
- On the next dialog if you have an external key server, feel free to use it, but it’s easier to use Azure Media Services for this.
- Next set the Key Delivery From Azure Media Services to Yes and use only one policy. Since you’re using AMS for the license acquisition you don’t need the Key Acquisition URL set.
- With AES on the next dialog you have two options for the Content key’s authorization policy option. The Open option does not require any authentication. If you don’t care who views the video, but just want to encrypt it then this is the option to choose. If you want to authenticate viewers then choose Token. That’s what we will focus on here.
- In this example for the Token Type we will choose JWT – JSON Web Token with symmetric key.
- For Token Properties set the issuer and audience. Typically for the Issuer it will be your company’s web site. The Audience or scope will be a subset of who you want to have access to the video. This allows you to specify different groups that can have access. For example, if you wanted only the marketing team to have access you could set it to urn:marketing assuming you have a way of providing a token only for people from the marketing team.
- You can specify additional claims if you wish.
You actually don’t have to have any claims in the token, but I’d recommend that you minimally set the Issuer field. The audience or scope is just used to restrict the token to specific groups in an organization. Another scenario would be authenticating multiple customers that used your service. If their content was actually comingled in your Media Services account you could set a scope for Company A for one piece of content and the scope for Company B for another. It all uses the same set of tokens, but restricts what it applies to. Claims are best described on https://en.wikipedia.org/wiki/Claims-based_identity. The claims in the token must match those configured for the key (or license). In other words, what you set when you apply DRM to an asset must match what your token service includes with for the claim. In a multiple company scenario where you are hosting content for two different client companies, what that would mean is that you’d set the issuer to be your company’s domain name. For the audience you could use a value of your client's company name ‘Company A’. Whenever you issue tokens for that company you’d need to include both your company’s domain name as the issuer and ‘Company A’ for the scope. For ‘Company B’ you’d just set the scope on their content to ‘Company B’ and issue tokens for them.
In Azure Media Services Explorer, after going through the steps the encryption policies will be applied to the asset. You will see in the Explorer status pane that several things are created including the content key ID and a sample Bearer token. This bearer token can be use temporarily to test playback of the encrypted content. You can also see this information and more by double clicking on the asset and going to the Content keys as well as Delivery policies tabs. I’ve included an example bearer token here:
On the Content keys tab you can get a new test token and specify the expiration and other options if you wish. This process is of course manual and not helpful outside of testing. For a full workflow you would want to run your own token generation service as part of your website. There’s a number of third party options for doing that. I’d suggest just searching for options on that https://www.bing.com/search?q=jwt+token+service. But essentially the idea is:
- You validate that a user logged into your website has a valid account (simply by logging in).
- You figure out what group / audience they’re part of if needed.
- You build the token payload that includes the following fields:
a. urn:microsoft:azure:mediaservices:contentkeyidentifier – (Required) This identifies specific key to unlock. Without this value the service would not know what to issue a key for.
b. iss – (Optional) The issuer of the token.
c. aud – (Optional) The audience / scope that I explained before.
d. exp – (Optional) This is the JWT token expiration. You should expire it, otherwise it could be reused by someone else.
e. nbf – (Optional) This is essentially a start time, or “not before” time. Used along with exp this gives you a time range that the JWT token is valid.
- When generating the signature you just need to sign it based on the symmetric key of the asset. If you’re in Azure Media Services Explorer, this is on step 3 of adding dynamic encryption to the asset on the dialog where you’re setting the Token Type, but on the Symmetric token key tab. Because you are signing your token based on this key you will need to keep this in your database. In AMSE you can get the symmetric key after encryption by double clicking on the asset, going to Content keys, selecting the Token option and clicking on the See key value button next to Primary Verification Key.
To give you an example of the token construction, paste in the example token from above into https://jwt.io/. Paste in
(my symmetric key) for the VERIFY SIGNATURE box and check the secret base64 encoded box. You can see the entire token now and verify that the signature is good. Note that in a production environment you would not share your symmetric key with anyone.
Hopefully your JWT token service is now generating tokens that work with Azure Media Services. The final thing to do is to include this token when you dynamically build your web page for the streaming content. There is documentation on the Player page at http://amp.azure.net/libs/amp/latest/docs/index.html#protected-content that explains how to include your bearer token.