Azure Front Door with Azure Storage Blobs

Artem Shaturskyi 145 Reputation points
2025-02-06T16:30:05.2733333+00:00

Hello!
We have an Azure Blob Storage account containing a large number of media files (.MP4). These files are manually organized into categorized folders under a single container. Our goal is to allow all corporate users to access the container and watch the media files directly in their browsers - no streaming or additional services, just simple playback.

I initially tried using Static Website Hosting with a pre-generated index.html, but generating SAS tokens for every file is not a feasible solution due to the large number of files.

I decided to implement Azure Front Door for the storage account, and it seems to work for file access, but I can't configure it to require user authentication.
How can I configure Azure Front Door to enforce Microsoft Entra ID authentication for accessing storage resources?

Azure Front Door
Azure Front Door
An Azure service that provides a cloud content delivery network with threat protection.
756 questions
Azure Storage Accounts
Azure Storage Accounts
Globally unique resources that provide access to data management services and serve as the parent namespace for the services.
3,384 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Vallepu Venkateswarlu 475 Reputation points Microsoft Vendor
    2025-02-21T13:55:25.9166667+00:00

    Hi @Artem Shaturskyi

    Welcome to the Microsoft Q&A Platform.

    Thank you for reaching out, & I hope you are doing well.

    Play your video files using the Storage Account Static Website with Entra ID authentication by following the steps below.

    1. Create an app registration by navigating to Microsoft EntraID > App registrations > New registrations.
    2. Add the redirect URL as static website endpoint url and localhost urlbelow.

    enter image description here

    1. Enable the tokens for auto-authorization in application.

    enter image description here

    1. Configure the storage account with Entra ID authentication as below.

    enter image description here

    1. Configure CORS settings with required permissions in storage account.

    enter image description here

    1. Configure the container access level to Private.

    enter image description here

    Storage account Static Website Url

    enter image description here

    Upload the index.html file below into the $web container, and make sure to replace it with your Application ID, Tenant ID, and Storage Website URL.

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Secure Video Gallery</title>
        <script src="https://alcdn.msauth.net/browser/2.29.0/js/msal-browser.min.js"></script>
        <style>
            body {
                font-family: Arial, sans-serif;
                text-align: center;
            }
            #video-list {
                margin-top: 20px;
            }
            .video-item {
                cursor: pointer;
                padding: 10px;
                border: 1px solid #ccc;
                margin: 5px;
                display: inline-block;
                background-color: #f9f9f9;
            }
            .video-item:hover {
                background-color: #ddd;
            }
            video {
                width: 80%;
                margin-top: 20px;
            }
            #logout-btn {
                display: none; /* Hide logout button initially */
                margin-top: 10px;
                background-color: red;
                color: white;
                border: none;
                padding: 10px;
                cursor: pointer;
            }
            #auth-message {
                margin-top: 15px;
                font-weight: bold;
                color: green;
                display: none; /* Hide the message initially */
            }
        </style>
    </head>
    <body>
        <h2>Secure Video Gallery</h2>
        <button id="login-btn" onclick="signIn()">Sign in with Entra ID</button>
        <button id="logout-btn" onclick="signOut()">Sign Out</button>
        
        <div id="auth-message"></div> <!-- Authentication Success Message -->
        <div id="video-list">Please sign in to view videos.</div>
        <video id="video-player" controls crossorigin="anonymous" preload="auto">
            <source id="video-source" src="" type="video/mp4">
            Your browser does not support the video tag.
        </video>
        <script>
            // Azure Entra ID Authentication Configuration
            const msalConfig = {
                auth: {
                    clientId: "2487cxxxxxxxxxxxxxxx136163cc3502", // Replace with your Azure AD App Registration Client ID
                    authority: "https://login.microsoftonline.com/<Tenant_ID>", // Replace with your Tenant ID
                    redirectUri: "https://venkatstofragetest.z13.web.core.windows.net/" // Your Static Website URL
                }
            };
            const msalInstance = new msal.PublicClientApplication(msalConfig);
            const blobListUrl = "https://venkatstofragetest.blob.core.windows.net/$web?restype=container&comp=list";
            const storageScope = "https://storage.azure.com/user_impersonation"; // OAuth Scope for Azure Storage
            function updateUI(isAuthenticated) {
                document.getElementById("login-btn").style.display = isAuthenticated ? "none" : "inline-block";
                document.getElementById("logout-btn").style.display = isAuthenticated ? "inline-block" : "none";
                document.getElementById("auth-message").style.display = isAuthenticated ? "block" : "none";
                if (isAuthenticated) {
                    document.getElementById("auth-message").innerText = "βœ… Authentication successful.";
                } else {
                    document.getElementById("auth-message").innerText = "";
                }
            }
            async function signIn() {
                try {
                    const response = await msalInstance.loginPopup({
                        scopes: [storageScope]
                    });
                    console.log("βœ… Signed in:", response.account);
                    updateUI(true);
                    fetchVideos(); // Fetch videos after login
                } catch (error) {
                    console.error("πŸ”΄ Login failed:", error);
                    document.getElementById("video-list").innerHTML = `<p>Login failed. Please try again.</p>`;
                }
            }
            async function signOut() {
                try {
                    await msalInstance.logoutPopup();
                    console.log("βœ… Signed out");
                    updateUI(false);
                    document.getElementById("video-list").innerHTML = `<p>Please sign in to view videos.</p>`;
                } catch (error) {
                    console.error("πŸ”΄ Logout failed:", error);
                }
            }
            async function fetchVideos() {
                try {
                    const account = msalInstance.getAllAccounts()[0];
                    if (!account) {
                        document.getElementById("video-list").innerHTML = `<p>Please sign in to view videos.</p>`;
                        return;
                    }
                    console.log("πŸ”Ή Fetching access token...");
                    // Acquire Access Token for Blob Storage
                    const tokenResponse = await msalInstance.acquireTokenSilent({
                        scopes: [storageScope],
                        account: account
                    });
                    if (!tokenResponse || !tokenResponse.accessToken) {
                        throw new Error("πŸ”΄ Failed to obtain access token.");
                    }
                    console.log("βœ… Access Token Received:", tokenResponse.accessToken);
                    // Fetch video list with Authentication
                    const response = await fetch(blobListUrl, {
                        method: "GET",
                        mode: "cors",
                        cache: "no-cache",
                        headers: {
                            "Authorization": `Bearer ${tokenResponse.accessToken}`,
                            "x-ms-version": "2020-06-12",
                            "Accept": "application/xml"
                        }
                    });
                    if (!response.ok) {
                        throw new Error(`πŸ”΄ HTTP error! Status: ${response.status}`);
                    }
                    const text = await response.text();
                    console.log("πŸ”Ή Blob XML Response:", text);
                    const parser = new DOMParser();
                    const xml = parser.parseFromString(text, "application/xml");
                    const blobs = xml.getElementsByTagName("Blob");
                    let videoList = document.getElementById("video-list");
                    videoList.innerHTML = ""; // Clear previous list
                    let videoFound = false;
                    for (let i = 0; i < blobs.length; i++) {
                        let fileName = blobs[i].getElementsByTagName("Name")[0].textContent;
                        let fileUrl = `https://venkatstofragetest.blob.core.windows.net/$web/${encodeURIComponent(fileName)}`;
                        // Only add MP4 files
                        if (fileName.toLowerCase().endsWith(".mp4")) {
                            videoFound = true;
                            let videoItem = document.createElement("div");
                            videoItem.className = "video-item";
                            videoItem.textContent = fileName;
                            videoItem.onclick = function () {
                                let videoSource = document.getElementById("video-source");
                                let videoPlayer = document.getElementById("video-player");
                                videoSource.src = fileUrl;
                                videoPlayer.load();
                                videoPlayer.play(); // Ensure playback starts
                            };
                            videoList.appendChild(videoItem);
                        }
                    }
                    if (!videoFound) {
                        videoList.innerHTML = "<p>No videos found.</p>";
                    }
                } catch (error) {
                    console.error("πŸ”΄ Error fetching video list:", error);
                    if (error.message.includes("401")) {
                        document.getElementById("video-list").innerHTML = `<p>Unauthorized. Please check storage permissions.</p>`;
                    } else if (error.message.includes("403")) {
                        document.getElementById("video-list").innerHTML = `<p>Forbidden. You may not have access to this storage account.</p>`;
                    } else if (error.message.includes("CORS")) {
                        document.getElementById("video-list").innerHTML = `<p>CORS issue detected. Ensure Azure Storage CORS settings are correct.</p>`;
                    } else {
                        document.getElementById("video-list").innerHTML = `<p>Error loading videos. Please try again later.</p>`;
                    }
                }
            }
            // Check if the user is already signed in
            window.onload = () => {
                const account = msalInstance.getAllAccounts()[0];
                if (account) {
                    console.log("πŸ”Ή User already signed in:", account);
                    updateUI(true);
                    fetchVideos();
                }
            };
        </script>
    </body>
    </html>
    
    
    

    Once you have completed all the steps, try accessing the static website URL in a browser. You will see the page as shown below.

    enter image description here

    Azure AD authentication page

    enter image description here

    Here is the result after signing in with Entra ID authentication.

    Note: Make sure to assign the required role to access the Blob, Like Storage Blob Data Contributor

    enter image description here

    Here is the result if someone without the required role tries to access it.

    enter image description here

    If you want to access the static website URL within a private network, you can enable a Private Endpoint in the Storage Account and disable public access in the firewall.

    Reference: Use private endpoints for Azure Storage

    I hope this helps to resolve your issue.


    Please don’t forget to close the thread by clicking "Accept the answer" wherever the information provided helps you, as this can be beneficial to other community members.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.