I am gonna show you what I did to prevent videos link sharing, so they’re only available for subscribed users.
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.
“A user is guilty until proven innocent”
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’:
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:
So when our API responds with an error, the
error 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! 😄