Designing an Authentication Framework for Video Streaming

Designing an Authentication Framework for Video Streaming

- Case study of video manual service based on ReactPlayer -

1. Project overview

This case is a project conducted to convert the existing PDF-based user manual system into a video content-based service. In the existing system, when users click the manual button, the frontend directly accesses AWS S3 to download the PDF file. While this method was simple to implement, it had limitations as users found it difficult to check the manual and the actual work screen simultaneously, and it was challenging to convey complex procedures intuitively.

The client requested a PIP (Picture in Picture) feature that allows users to view manual videos while maintaining the work screen. At the same time, due to security policies, direct access to AWS S3 had to be restricted, and there were also constraints that sensitive authentication information could not be included in the URL parameters. Therefore, the core of this project was not merely implementing a simple video playback function, but designing an authentication and streaming structure that satisfies both browser-based video playback architecture and security requirements.

2. Technology Selection and Design Direction

In the frontend area, we introduced ReactPlayer, a React-based video player library. ReactPlayer operates based on the HTML5 video tag and has high compatibility with the React environment, as well as the advantages of relatively simple PIP functionality and playback state control.

However, ReactPlayer uses the request method of the video tag internally, so the video file request is performed using the GET method by default. Since it is difficult to include authentication information in the request body or freely configure headers like a typical API call, it was necessary to design a separation between the authentication process and the actual video playback request.

Sample code 1. Example of calling ReactPlayer


url={videoEndpoint}
controls
pip
playing={false}
width="100%"
height="100%"
/>

The above example illustrates the structure in which ReactPlayer plays a video based on the video playback endpoint received from the server. The authentication information is not included in the URL and is handled by passing a temporary token issued during the pre-authentication phase via a Cookie.

3. Architecture Redesign

The existing structure allowed the Frontend to directly access AWS S3. However, maintaining the same structure when providing video content could lead to exposure of storage paths, URL reuse, and potential bypass of access controls. Therefore, we have separated the server roles as follows.

Frontend
-> Server A (User authentication and streaming request relay)
-> Server B (file read-only server)
-> AWS S3

Server A is responsible for user authentication, authorization validation, temporary token issuance, and streaming request relay. Server B has been separated to only handle actual video file retrieval and AWS S3 access. This is to prevent the client from knowing the storage path directly and to ensure that all video requests pass the server's authentication validation.

4. Authentication and Playback Flow

When the user clicks the manual button, it does not immediately call the video player, but first requests the user validation API from Server A. Once the validation is complete, Server A issues an endpoint for video playback and a time-limited temporary token. The temporary token is stored in the browser cookie and is sent along with the video endpoint request when ReactPlayer calls it.

Sample Code 2. Video Playback Information Request

const openManualVideo = async (manualId: string) => {
const response = await api.get(`/api/videos/${manualId}/authorize`);
setVideoEndpoint(response.data.videoEndpoint);
setManualModalOpen(true);
};

This code is an example of requesting the video playback endpoint when the manual button is clicked. At this stage, the server responds by validating the user's permissions and storing a temporary token in the Cookie.

Sample Code 3. Example of Issuing Temporary Token Cookie

ResponseCookie cookie = ResponseCookie.from("VIDEO_ACCESS_TOKEN", token)
.httpOnly(true)
.secure(true)
.path("/api/videos/")
.maxAge(Duration.ofMinutes(30))
.sameSite("Strict")
.build();

return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.body(new VideoAuthorizeResponse(videoEndpoint));

The Cookie has been configured with HttpOnly, Secure, and SameSite options to limit script access and unnecessary external transmission. Additionally, it has been designed to be used restrictively only for video requests by specifying the path and maxAge.

5. Streaming Broadcast Processing

Video streaming continuously delivers large amounts of data, unlike regular file downloads, and partial requests based on the Range Header may occur when users move the playback position. Thus, Server A must pass the client's Range Header to Server B and relay Server B's response status and key headers back to the client.

Sample Code 4. Streaming Proxy Based on Range Header

@GetMapping("/api/videos/{manualId}/stream")
public Mono >> stream(
@PathVariable String manualId,
@RequestHeader(value = HttpHeaders.RANGE, required = false) String range
) {
return webClient.get()
.uri("/internal/files/{manualId}", manualId)
.headers(headers -> {
if (range != null) headers.set(HttpHeaders.RANGE, range);
})
.exchangeToMono(response -> {
Flux body = response.bodyToFlux(DataBuffer.class);
ResponseEntity.BodyBuilder builder = ResponseEntity.status(response.statusCode());
response.headers().asHttpHeaders().forEach((name, values) -> {
if (isStreamingHeader(name)) builder.header(name, values.toArray(String[]::new));
});
return Mono.just(builder.body(body));
});
}

The key of this method is that it does not load the entire file into memory, such as bodyToMono(Resource.class) or bodyToMono(byte[].class). By using bodyToFlux(DataBuffer.class), video data can be delivered in chunks, making it suitable for large-scale video processing.

Sample Code 5. Key Streaming Header Filtering

private boolean isStreamingHeader(String name) {
return HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)
|| HttpHeaders.CONTENT_RANGE.equalsIgnoreCase(name)
|| HttpHeaders.ACCEPT_RANGES.equalsIgnoreCase(name)
|| HttpHeaders.CACHE_CONTROL.equalsIgnoreCase(name);
}

Headers such as Content-Range, Accept-Ranges, and Content-Length are necessary for the browser to determine the length of the video and the range of partial responses. It is especially important to preserve these headers for navigation and stable playback.

6. Results and Effects

As a result of the implementation, users were able to instantly play videos in the browser and utilize both the actual work screen and video manual simultaneously through the PIP function. Additionally, by removing direct access to AWS S3 and applying server-based access control, we were able to meet security requirements.

• Remove direct exposure of AWS S3

• Remove transmission of sensitive information based on URL

• Allow access to video endpoint after user validation

• Restricted access control based on temporary tokens

• Support for video playback and navigation based on Range Header

7. Conclusion

Through this case, I experienced a design case that not only involved adding a video player but also considered the operation of ReactPlayer and the HTML5 video tag, the customer's security policy, the separation of roles between servers, and the streaming processing method comprehensively. By separating the authentication and playback processes and clearly dividing the responsibilities of Server A and Server B, I was able to secure both user experience and security.

In particular, I felt that in a practical environment, understanding the constraints of security policies and browser operation methods is more important than the implementation of functionalities themselves. This project confirmed that, in video-based manual services, it is essential to consider authentication structure, data flow, streaming header processing, and operational security policies for reliable service provision.

NZ

Site footer