awslabs / amplify-video

An open source Category Plugin for the AWS Amplify-CLI that makes it easy to deploy live and file based streaming video services and integrate them into your Amplify applications.
https://www.npmjs.com/package/amplify-category-video
Apache License 2.0
267 stars 56 forks source link

Adding Signed Cookie Option #289

Open djsjr opened 3 years ago

djsjr commented 3 years ago

I cannot currently use signed URLs with HLS videos in my flutter app because the video players available to flutter do not allow for appending tokens to the end of each request. I realized this was necessary from #236.

The standard flutter video player (as well as the widely used “just audio” player) both have a parameter for a map of http headers. Therefore, I suggest allowing content protection via signed cookies - which I believe would allow me to successfully access protected content by providing the signed cookie to the player.

if I am incorrect about this, or if there is a way to change the current set up to fulfill my need, please let me know!

djsjr commented 2 years ago

For anyone with a similar problem, I was able to take the token obtained through an API call, separate it into substrings for the Policy, KeyIdPair, and Signature, and then create a Map<String, String> with the [same format used here].(https://stackoverflow.com/questions/60773608/flutter-how-to-set-cloud-front-cookie-in-expo-video-player-plugin)

Take those substrings from the token string, make a map, and pass into the headers param.

      String cookieValue = '';
      cookieValue += "CloudFront-Policy=" + policy + ";";
      cookieValue += "CloudFront-Signature=" + signature + ";";
      cookieValue += "CloudFront-Key-Pair-Id=" + keyPaidId + ";";

      Map<String, String> cookie = {'Cookie': cookieValue};

      _videoPlayerController = VideoPlayerController.network(url, httpHeaders: cookie);

Video player is now working.

smp commented 2 years ago

@djsjr thanks for sharing your problem and solution with the community. Do you want to keep this ticket open to track a feature for optional cookie based support? Otherwise we can close as resolved. If you think it's appropriate, we can also add a note to the docs.

djsjr commented 2 years ago

Considering CloudFront specifically recommended signed cookies for HLS content, it'd probably be a good idea to add it as an option at least.

I do think a note on converting the signedURL to a cookie format could be helpful to others in the meantime. The trick is appending the params together with semi colons as one string and passing it as a single header, as I did. I've only tried it in Flutter, but others have made this work with ExoPlayer as well.

tsenguunchik commented 2 years ago

Did you test this on an actual iphone?

djsjr commented 2 years ago

@tsenguunchik The workaround? Yes

tsenguunchik commented 2 years ago

Wow that is surprising. I'm trying to use this exact thing on web with JS but failing miserably.

luciano-schirmer commented 2 years ago

@tsenguunchik I tested on actual iPhone 6S using React Native with Expo SDK v45 and expo-av and it works.

This is a simplified version of the example in Expo Video.

export default function App() {
  const video = React.useRef(null);

  const cookie = `CloudFront-Policy=${policy};CloudFront-Signature=${signature};CloudFront-Key-Pair-Id=${keyPairId}`;
  const headers = { Cookie: cookie };
  const source = { uri: foo, headers: headers };

  return (
    <View
      <Video
        ref={video}
        source={source}
      />
    </View>
  );
}

Note: policy, signature and keyPairId must be parsed from the token obtained through GraphQL API call.

Sample regex to obtain these variables:

const policy = /[?&]Policy=([A-Za-z0-9-_~]+)/.exec(token)[1];
const signature = /[?&]Signature=([A-Za-z0-9-_~]+)/.exec(token)[1];
const keyPairId = /[?&]Key-Pair-Id=(\w+)/.exec(token)[1];

Thank you @djsjr for sharing your achievements.