Samsung Smart TVs use a separate media player component for video streaming. The initial request passes session cookies, but subsequent HTTP range requests (which fetch the actual video chunks) do not. If you're seeing 0:00 / 0:00 on the video player with no playback, your range requests are probably failing authentication silently.
The Problem
I built a personal file vault: a self-hosted system for storing and streaming files securely over the web. The stack: an ASP.NET Core MVC frontend handling authentication, a Go backend serving files with token-based access, and nginx as a reverse proxy. Everything worked perfectly on desktop browsers and mobile devices.
Then I tried to watch a movie on my Samsung Smart TV.
Symptoms
The TV's Tizen browser navigated to my vault, authenticated successfully, and displayed the file browser without issues. I clicked on a video file. The video player UI appeared: controls, progress bar, everything looked normal. Except:
- The time display showed
0:00 / 0:00 - The video never loaded
- No error message appeared
- The player just sat there, indefinitely
No crash, no timeout, no feedback. Just a player that knew it was supposed to play something but couldn't.
System Context
The video streaming flow looked like this:
- Browser authenticates with ASP.NET Core, receives session cookie
- User requests video file via
/Vault/File?path=movie.mp4 - ASP.NET validates session, proxies request to Go backend
- Go serves file with proper range request support
- Browser receives stream and plays video
This worked everywhere except the Samsung TV. The question was: where in this chain was it breaking?
The Investigation
First Assumptions
I didn't have strong assumptions going in. I'd never tried streaming to a Smart TV before, so I didn't know what to expect. Initial research turned up fragmented forum posts about various Samsung models, most from years ago. Nothing directly applicable.
I started with the obvious candidates:
- Video encoding: Maybe the TV couldn't decode the file format? Tested with multiple MP4s encoded with h.264: same result.
- CORS issues: Perhaps the TV browser had stricter cross-origin policies? Headers looked fine in logs.
- Fetch API limitations: Samsung's Tizen browser might have incomplete JavaScript support? But the initial requests were succeeding.
None of these panned out. The authentication request worked. The file browser loaded. Something specific to video playback was failing.
Narrowing It Down
I enabled verbose logging on both servers and started comparing request patterns between desktop Chrome and the Samsung TV.
Desktop Chrome video playback showed a clear pattern:
// Initial request
GET /Vault/File?path=movie.mp4
Cookie: .AspNetCore.Session=abc123
Range: bytes=0-
// Subsequent range requests
GET /Vault/File?path=movie.mp4
Cookie: .AspNetCore.Session=abc123
Range: bytes=1048576-2097151
GET /Vault/File?path=movie.mp4
Cookie: .AspNetCore.Session=abc123
Range: bytes=2097152-3145727
HTTP
The session cookie was present on every request. Now I looked at the Samsung TV logs:
// Initial request - cookie present
GET /Vault/File?path=movie.mp4
Cookie: .AspNetCore.Session=abc123
Range: bytes=0-
// Subsequent range requests - no cookie
GET /Vault/File?path=movie.mp4
Range: bytes=1048576-2097151
GET /Vault/File?path=movie.mp4
Range: bytes=2097152-3145727
HTTP
The session cookie disappeared after the first request.
The Breakthrough
This explained the 0:00 / 0:00 display. The initial request succeeded— that's how the player knew it was a video and could render the UI. But every subsequent range request returned a 401 Unauthorized (or redirect to login), which the media player silently ignored.
The TV's video player component makes its own HTTP requests, separate from the browser's JavaScript context. It doesn't inherit cookies or session state from the webview. The initial metadata request happens through the browser (with cookies), but the actual streaming happens through a native media player (without cookies).
Samsung doesn't publish technical documentation about Tizen's media player HTTP behavior. This is an implementation detail of their embedded browser stack that you can only discover through debugging.
Root Cause
Samsung Smart TVs (and likely other Smart TV platforms) separate the webview from the media player at the system level. When you set a video source via JavaScript:
const video = document.createElement('video');
video.src = '/Vault/File?path=movie.mp4';
JavaScript
The browser hands that URL to a native media player process. That process:
- Makes its own HTTP requests
- Does not share the browser's cookie jar
- Does not share the browser's session state
- Cannot access JavaScript-managed authentication tokens
This is a security boundary. Samsung doesn't want media playback to leak browser state. But it means any authentication mechanism that relies on cookies or session state will fail for streaming video.
I attempted several workarounds within ASP.NET before accepting this limitation:
- Custom HttpClient: Tried bypassing ASP.NET's response processing, still failed because
Response.Bodygoes through the HTTP pipeline - Raw TCP streaming: Built a custom TCP client to forward raw bytes, still processed by ASP.NET's response handling
The fundamental issue: any response processed through ASP.NET's HttpContext.Response couldn't be made transparent enough for the Samsung media player. The TV worked when hitting the Go server directly, but failed when proxied through ASP.NET.
The Solution
Architecture
The solution was to bypass ASP.NET entirely for Samsung TV video requests, while maintaining security through a different mechanism. The new flow:
- Detect Samsung TV via User-Agent (
SMART-TVorTizenstrings) - For video files, redirect to a dedicated Go endpoint
- Go validates requests based on local network subnet (192.168.1.0/24)
- Go serves video directly to the TV's media player
The key insight: since I'd only ever use this on my home network, I could trade cookie-based authentication for network-based access control.
Implementation
On the JavaScript side, I detect Samsung TVs and redirect video requests:
async function previewFile(filePath, fileName) {
const userAgent = navigator.userAgent;
// Samsung TV detection - bypass normal auth flow
if (isVideoFile(fileName) &&
(userAgent.indexOf('SMART-TV') !== -1 ||
userAgent.indexOf('Tizen') !== -1)) {
// Direct to Go server endpoint
window.location.href = '/compatibility/file/' +
encodeURIComponent(filePath);
return;
}
// Normal flow for other devices...
}
JavaScript
The Go server validates Samsung TV requests by checking both the User-Agent and source IP:
func (s *SecureFileServer) samsungTVHandler(w http.ResponseWriter, r *http.Request) {
ip := s.getRealIP(r)
userAgent := r.UserAgent()
// Verify Samsung TV user agent
isSamsungTV := strings.Contains(userAgent, "SMART-TV") ||
strings.Contains(userAgent, "Tizen")
if !isSamsungTV {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
// Verify local network subnet
clientIP := net.ParseIP(ip)
_, subnet, _ := net.ParseCIDR("192.168.1.0/24")
if !subnet.Contains(clientIP) {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
// Serve the video file directly
s.streamingFileHandler(w, r)
}
Go
Security Tradeoffs
This solution accepts a deliberate tradeoff:
This approach allows any device on the local subnet with a Samsung TV User-Agent to access video files without authentication. This is acceptable for my use case (personal home network with controlled access), but wouldn't be appropriate for a production system serving untrusted clients.
The mitigations I have in place:
- Subnet restriction limits access to local network only
- User-Agent check prevents casual access from other devices
- The Go server is only accessible via localhost and local subnet, not exposed to the internet
- Router-level firewall rules control what devices can reach the server
For a production system, you'd want to implement signed URLs with short expiration times, generated by the authenticated ASP.NET session and validated by the Go server.
Key Takeaways
Debugging Checklist
Video player shows 0:00 / 0:00 with no playback on Smart TVs:
- Verify the video is being served with proper range request support (
Accept-Ranges: bytesheader). Without this, most Smart TVs will show "Function not supported." - If range requests work but you still see
0:00 / 0:00, check your server logs for the range requests. Are they receiving authentication credentials? - If the initial request has auth but subsequent range requests don't, you've hit this exact issue.
General Principles
- Embedded media players don't share browser state. This isn't just Samsung—expect similar behavior from any Smart TV, game console, or IoT device with embedded video playback.
- Cookie-based auth will break for streaming. If you're building anything that streams media to diverse clients, plan for token-based or signed-URL authentication from the start.
- When documentation doesn't exist, verbose logging is everything. The only way I found this was by comparing request headers between working and non-working clients.
- Sometimes the right solution is accepting constraints. I spent hours trying to make ASP.NET proxy transparent enough. The actual solution was recognizing that proxying was fundamentally incompatible and designing around it.
This took roughly 10-14 hours over a weekend to debug and solve. Most of that time was spent eliminating hypotheses that turned out to be wrong. The actual fix was maybe 50 lines of code across two files.
That's debugging: hours of investigation for minutes of implementation.