Our Expert Team

Our Unique Approach

Data Strategy & Architecture

Intelligence Platform Development

Change Management and Adoption

Life Sciences

Healthcare

Restaurants & Food and Beverage

Consumer Packaged Goods (CPG)

How We Actually Built It:The Technical Reality of Embedding a Legacy App

How We Actually Built It: The Technical Reality of Embedding a Legacy App | Rower Consulting
TECHNICAL DEEP-DIVE LEGACY MIGRATION ARCHITECTURE · ROWER CONSULTING USER BROWSER Curator Front End Nav + JS message handler EMBEDDED iFrame — Legacy Web App APP SERVER Nginx · Vue · Python/Flask DOCKER SAML Proxy · Redis · App SAML PROXY Node + Express saml-passport State: POST /get Identity via Curator API not Microsoft IDP PLATFORM Curator + REST API SAML SSO · Identity umbrella REDIS State persistence · User-keyed NAVIGATION Window Messaging API iFrame → Curator JS handler IDENTITY PROVIDER Microsoft Entra ID SAML · Curator as proxy STATE MANAGEMENT Vue Store + Mutations Subscribed · Staggered async sets CSP: frame-src / frame-ancestors Python, Flask, Vue, Nuxt, Docker, Nginx. Not helped by the quality of their implementations. Rower solved it anyway. 5+ technologies integrated 3 Docker containers orchestrated 0 interruptions to end users 60,000+ lines of legacy code — seamlessly wrapped
← Part 1: From Fragmented Data to Unified Intelligence
Technical Deep-Dive
Legacy Modernization Series · Part 2 of 2

How We Actually Built It:
The Technical Reality of Embedding a Legacy App

⚙ Legacy Modernization Series — Part 2: The Build

Part 1 covered the strategy: embed the legacy application inside the new platform, give users a seamless single-pane experience, and let the client migrate at their own pace — no downtime, no forced cutover. This post covers what that actually took to build — and the specific technical problems that stood between the plan and working software.

Python / Flask Vue / Nuxt Node / Express Docker Nginx SAML / saml-passport Redis Windows Messaging API

Step 1 — Getting the App into an iFrame

The first step was straightforward: modify the application’s Content Security Policy to permit embedding. In an Nginx-served application, that means setting frame-src and frame-ancestors to allow requests only from the platform domain. Once we had access to the config, this was a clean change.

We embedded the whole app in a single iFrame as a proof of concept. The OAuth login screen appeared as expected — followed immediately by a permission denied from login.microsoft.com.

⚠ Challenge

Microsoft does not allow authentication requests to originate from within an iFrame — by design, for good security reasons. The client also needed the application to remain independently accessible and secure outside the platform. So we couldn’t simply bypass auth.

Step 2 — Replacing OAuth with SAML

The platform has built-in support for SAML authentication, and the client’s Power BI environment was already on SAML. The natural move was to bring the legacy web app onto the same identity flow. With everything under the same hood, SSO from the platform login would extend to the application — no re-authentication prompt, no iFrame-blocked Microsoft request.

The application was running in Docker, and the existing OAuth proxy was already isolated in its own container. That made the swap clean: replace the OAuth proxy container with a custom SAML proxy built on Node Express and saml-passport. SAML authentication now protected the web app itself.

⚠ Challenge — Round Two

With SAML in place, we embedded the app again. Permission denied. Having multiple applications authorized via SSO through the same identity provider does allow a single sign-on for the user — but each application still fires an auth check in the background. And that check is still blocked from within an iFrame.

✓ Solution

An alternate authorization path. The platform exposes a REST API (and the support team was genuinely helpful here). When the legacy app detects it’s running inside an iFrame, the SAML proxy container reaches out to the platform’s API rather than Microsoft to obtain identity. The embedded app now operates under the platform’s SAML umbrella entirely — the Microsoft IDP check never fires. Pages rendered correctly, securely, inside the iFrame.

With auth solved, the next step was navigation. The legacy application’s nav bar needed to disappear when embedded — replaced entirely by the platform’s menu — while still driving the correct page loads inside the iFrame.

A conditional render on the navigation bar handled the hide. For communication between the iFrame and the platform, the Windows Messaging API was the right tool: when a link inside the app is clicked, the app posts a message to its parent iFrame. JavaScript on the platform’s front end picks that up and loads the appropriate page. Despite the application’s complexity, the number of distinct page links was manageable, and this worked cleanly.

Step 4 — State Persistence Across iFrame Loads

Initially the state footprint looked small. A handful of parameters could ride the messaging system — the platform would relay them after each new iFrame loaded. It worked, with some workarounds for a quirky cascade of asynchronous store changes that fired when certain values were set.

Then we discovered the persistence ran deeper than expected.

⚠ Challenge

Three variables needed to persist across all iFrame page loads for all users. Messaging alone wasn’t going to handle this reliably. And the async cascade problem — where setting one store value triggered a ripple of downstream mutations — meant a naive approach would overwrite values before they’d been read.

✓ Solution

Redis was already in the Docker stack as part of the SAML proxy setup. We used Vue’s mutation subscription to sync the required variables to user-keyed Redis entries, and added fetch logic to retrieve and set them in the store on load. A second Axios module pointed at the SAML proxy container handled the transport, with POST and GET endpoints for state added to the proxy.

The cascade problem had a pragmatic fix: asynchronously stagger the sets by a small delay. Not the cleanest solution — a proper overhaul with completion hooks would have been better — but with the application slated for deprecation, that was juice not worth the squeeze. Staggered sets gave us reliable persistence across iFrame page loads.

The Result

Python and Flask and Vue, Nuxt and Docker and Nginx — five-plus technologies, not helped by the quality of their existing implementations. The Rower team traversed every one of these pitfalls because of combined breadth of experience across the stack.

✓ What Was Delivered

A legacy application — 60,000+ lines of fragmented code — fully embedded inside a modern platform. Secure SAML authentication with no Microsoft iFrame conflicts. Navigation controlled by the platform. State persisted across page loads via Redis. End users saw nothing change. The client got the transition runway they needed.

If you’re facing a similar situation — a legacy system that can’t be torn down overnight, users who depend on it daily, and a modernization target that keeps moving — this is the kind of problem Rower is built for.

Technologies & Partners

Tableau ThoughtSpot Power BI Snowflake Microsoft Azure Alteryx dbt Sigma

Other Resources

Start your journey

Accessibility Statement

At Rower Consulting, we are committed to ensuring digital accessibility for everyone, including individuals with disabilities. We strive to continually improve the user experience for all visitors and apply the relevant accessibility standards of WCAG 2.1 (Web Content Accessibility Guidelines).

If you encounter any accessibility barriers or have suggestions for improving our website’s accessibility, please contact us through our Contact Form and we will work to address the issue.

Privacy Policy

1. Introduction

Welcome to Rower Consulting (“we,” “our,” or “us”). We are committed to protecting your personal information and your right to privacy. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you visit our website https://rowerconsulting.com (the “Site”).

Please read this privacy policy carefully. If you do not agree with the terms of this privacy policy, please do not access the site.

2. Information We Collect

We collect information in two ways:

  1. Information you provide to us:
    • Personal information that you voluntarily provide to us when you fill out forms on our Site.
    • This may include your name, email address, and any other information you choose to provide in the form fields.
  2. Information collected automatically:
    • We use Google Site Kit, which integrates several Google services to collect and analyze data about our website visitors.
    • This may include information such as your IP address, browser type, operating system, referring URLs, device information, pages visited, and the dates/times of visits.

3. How We Use Your Information

We use the information we collect for the following purposes:

  • To respond to your inquiries or requests
  • To provide you with information or services you have requested
  • To improve our website and user experience
  • For internal record keeping and administration
  • To analyze website traffic and optimize user experience using Google Site Kit

4. Google Site Kit

We use Google Site Kit to help us understand how visitors interact with our website and to improve our services. Google Site Kit integrates several Google services, which may include:

  • Google Analytics: for website traffic analysis
  • Google Search Console: for search performance data
  • Google AdSense: for advertising performance (if applicable)
  • Google PageSpeed Insights: for website performance data

These services collect non-personally identifiable information which may include:

  • Website traffic data
  • Search query data that led to our site
  • Indexing data
  • Data about how visitors interact with our site
  • Website performance metrics

This information helps us to improve our website and its content. Google’s ability to use and share information collected by Google Site Kit is restricted by the Google Site Kit Terms of Service and the Google Privacy Policy. You can learn more about how Google uses data when you use our site by visiting https://www.google.com/policies/privacy/partners/.

5. How We Protect Your Information

We are committed to ensuring that your information is secure. We have implemented suitable physical, electronic, and managerial procedures to safeguard and secure the information we collect online to prevent unauthorized access or disclosure.

6. Third-Party Sharing

We do not sell or lease your personal information to any third parties. However, aggregated, anonymized data collected through Google Site Kit may be shared with Google as part of the service’s functionality.

7. Cookies and Tracking Technologies

We use cookies to improve your experience on our website. These cookies may collect non-personal information. You can choose to accept or decline cookies. Most web browsers automatically accept cookies, but you can usually modify your browser setting to decline cookies if you prefer.

Google Site Kit may use cookies to collect information. You can learn more about how Google uses cookies by visiting https://www.google.com/policies/privacy/partners/.

8. Your Rights

Depending on your location, you may have certain rights regarding your personal information, such as the right to access, correct, or delete your data. Please contact us if you wish to exercise these rights.

9. Changes to This Privacy Policy

We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page.

10. Contact Us

If you have any questions about this Privacy Policy, please contact us

Download Rower’s Executive Decision Systems™ Framework​

Get instant access to our proprietary 4-phase methodology.