How did I secure videos using Laravel and JavaScript?

I am gonna show you what I did to prevent videos link sharing, so they’re only available for subscribed users.

Image for post
Image for post

I was working on an e-learning website where users obviously gonna watch videos, but the problem was, how to prevent subscribed users from sharing a video source with other unsubscribed users?

To secure getting the video source from the database is easy, you can use middlewares or anything that controls access. But after getting the link, it’s hard to prevent the user from copying the link from the source of the web page and share it.

I kept looking on internet for long time, but I didn’t find an efficient way, even many devs were saying it’s impossible and you can only make it harder for the user to get it.

Making it harder means you:

  • Disable the context menu (the right click)
  • Obscure the URL
  • Change the URL frequently

Some other solutions I found but those didn’t suit my requirements and the client’s budget:

  • Make them view it in a custom-built “custom-served” video player
  • Use a video streaming service already available

You’ll find an explanation of the above techniques following this link to Stackoverflow.

I almost gave up and accepted the idea of ‘’just make it as hard as you can” and my last shot was to try Laravel Signed URLs. It basically appends a “signature” hash to the query string which allows Laravel to verify that the URL has not been modified since it was created. We gonna use specifically temporarySignedRoute method, which means the server generates a URL that expires in a specific period which we choose.

To start with, I added these two lines in ‘routes/api.php’:

Don’t mind my naming choice pls 😅

As you can see, I assigned the ‘signed’ middleware to the second route, that’s why we need to add a line to the $routeMiddleware array in ‘app/http/Kernel.php’

Then in ‘VideoController.php’, I implemented both of those methods:

Please read carefully the comments in the code because I thought it’s better to explain line by line.

After that, on the client side, we request a specific video URL using the first route like so:

Still, this is not enough, because if the user seeks an unloaded part of the video after the link expiration, he’ll be blocked too. That’s where we solve the issue using JavaScript. Actually, we need the error (the server not responding with a valid link) to occur, that’s the fun part. Here’s the code I used:

The part we need in the HTML file
The part we need for the JS file

So when our API responds with an error, theerror event on the video will fire off and we’ll send another request which is identical to the one we sent to get the secure video link in the first place. Then we need to play the video from the exact sought point, so we save it using the currentTime method. We set again the video source, we reload it using load, we seek the point we need when the metadata has been loaded, and finally we play the video.

Maybe at this point, you’re wondering about the user experience, like are we gonna do all that while the user still waiting for the video to play again? But you shouldn’t worry about it, it’ll be quick and the user will think it’s only seeking the needed point and streaming servers are already powerful so it should be a fast process.

Also, it’s better to mention that the video player will still load the video data even after the link expiration, so if the user just keep watching without seeking any unloaded part, it’ll work perfectly.

So with that, I think I succeeded preventing link sharing, even if our users know how to play with the dev tools, especially the network tab, they will still fail cause it’s almost impossible to copy the secure link, to send it and to open the video in just 5 seconds.

Feel free to ask or to give your feedback about my solution in the comments section, that will help me make sure it works as expected.

Thank you for reading and seeya soon! 😄

A student who loves to talk about Business and Web Development

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store