Implementing Access-Controlled Video Streaming for an EdTech MVP
I had to solve an interesting problem, It involves video streaming solution and access control for a ed-tech platform MVP . There requirements were
- admin can upload videos
- only logged in users would be able to view / stream vidoes
- students would be able to see only the videos of the courses they have access to
- adaptive bit rate streaming would be good to have
since had to come up with something quick I was searching for existing open source solutions , I looked throught projeccts like antmedia, owncast, jellyfin, emby and a few others , but settled with mediacms as it was very similar to youtube and had adaptive bit rate streaming support
but now the remaining thing to solve were the auth for the admin access control for students .
Nginx to the rescue !
I put the admin access for mediacms on a domain and student video stream url on another , for example media-admin.somesite.com
and play.somesite.com
.
for admin access put a basic auth on the admin domain
Now the interesting part, for student video streaming , when a user / student loggs in to the app / website somesite.com
they would be given a jwt which I would reuse for the access control of the video streaming , when a request is made to the streaming url (play.somesite.com
) add a query param (or header) token to the url so it would look like play.somesite.com?q=qwe&token={jwt}
and here is the nginx config
http {
# resolver 127.0.0.11 valid=30s;
upstream web {
server web:80;
}
upstream auth_service {
server auth_service:3000;
}
server {
listen 80;
server_name localhost;
# Enable error logging for debugging
error_log /var/log/nginx/error.log debug;
access_log /var/log/nginx/access.log;
location = /auth {
# internal;
# Add more detailed logging for auth requests
# proxy_pass http://auth_service/verify-token?tok=$arg_tok;
proxy_pass http://auth_service/verify-token?$args;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
# Add additional headers that might be needed
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Increase timeout for auth requests
proxy_connect_timeout 10s;
proxy_read_timeout 10s;
}
# Add a location for unauthorized access
location = /unauthorized {
return 401 "Authentication required";
}
location /view {
auth_request /auth;
proxy_pass http://web;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-CSRFToken $http_x_csrf_token;
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
# Add error handling for auth requests
error_page 401 403 =401 /unauthorized;
}
location / {
proxy_pass http://web;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-CSRFToken $http_x_csrf_token;
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
}
}
}
after the request reaches nginx it is first passed to an authentication service to validate the token , if the token is valid and if the token has access to the course video the auth service would return 200 else 400
so the request will proceed to the mediacms hosted video and provide response if the token is valid 🙌 .
And if anyone tries to access directly thorugh the video url without a valid token they would just see 400