Goodbye Legacy Tokens, Hello NAA: A Developer's Survival Story
How I accidentally became almost an NAA expert by just trying to make Outlook work (and breaking it a few times)
Hi everyone, I am Vaibhav, MTS-1 at Fyle. Over the past two months, I’ve been on a rollercoaster journey — decoding how Microsoft Outlook add-ins work while working on one of the business-critical initiatives at Fyle. What started as a simple “just replace the old token method with the new one” quickly turned into Microsoft's version of Inception — layers of documentation, legacy code, and unexpected bugs wrapped inside each other.
I didn't choose the migration life, the migration life chose me.
If you're here looking for the perfect guide to NAA migration or If you're here to read about someone suffering through Microsoft's documentation with a sprinkle of memes — you're in the right place. Let's dive in!
The Great Outlook Add-in Migration
Just as I wrapped up one of my initiatives, Dimple, my manager, called me to discuss what I'd be working on next. The task? Updating our Outlook add-in to align with Microsoft's latest changes. They were deprecating getCallbackTokenAsync()
, which meant we had to migrate our entire authentication flow to Nested App Authentication (NAA) — a more secure, streamlined approach using Single Sign-On (SSO) and Microsoft Graph APIs instead of old Outlook REST APIs.
At first, I thought, how hard could it be?
Spoiler alert: very hard.
What I thought would be a simple migration turned into a journey that tested not just my technical skills but also my patience, problem-solving abilities, and faith in Microsoft's documentation labyrinth. This blog is a mix of technical insights, hard-learned lessons, and the occasional what-is-even-happening-anymore moment — all from someone who lived to tell the tale.
Why does this Migration Matter?
At Fyle, our Outlook add-in is a critical feature — it allows customers to seamlessly add expenses straight from their emails. This migration initiative wasn’t just a tech upgrade; It was a business-critical initiative. Without it, our key feature of attaching receipts directly from emails would break down, forcing customers into more manual work and preventing our OCR from automatically extracting and filling data from receipts by the end of February 2025.
Abhishek, our Senior Engineering Director, kept a close eye on this initiative to ensure everything went smoothly. The weight of responsibility was heavy, but so was the excitement to solve this.
How Hard Could It Be?
Microsoft’s documentation outlined a clear migration path:
Register an Azure AD App with the necessary permissions.
Use MSAL.js library to acquire tokens.
Use Microsoft Graph APIs instead of legacy Outlook REST APIs.
Update redirect URIs so that SSO redirection works seamlessly.
Sounds simple, right? Well, reality had other plans.
The SSO Redirection Puzzle
One of the biggest challenges was to understand how the SSO redirection works — how Outlook guides the user through SSO and then brings them back to the add-in.
If you're curious about what NAA is and the changes it brought, here’s a flowchart from Microsoft that outlines how a token is acquired via SSO and then used to retrieve email details like user information and mail.
After a lot of trial and error, I discovered the magic of redirect URIs on Microsoft's Entra ID platform. This seemingly small detail took hours of debugging to pinpoint. I used console.log extensively to compare the sample code with our Fyle add-in implementation. Trust me — never hesitate to use console.log()
for debugging, as it can save you a lot of time. In the end, I realized that a slight mismatch in the redirect URI was preventing the flow from returning to Outlook.
Diving into the Codebase: A Legacy Mystery
Our codebase presented several challenges typical of legacy systems:
Older Syntax: The code was written using ES5 syntax, prevalent before the introduction of ES6. This meant no arrow functions, classes, or modules, making the code less modular and harder to maintain.
Promise Handling: Asynchronous operations were managed using callback functions instead of Promises. This resulted in deeply nested structures, commonly referred to as callback hell, making the code harder to read and debug.
Browser Compatibility: Since Outlook add-ins run on some-webview engines (including Internet Explorer 11 for legacy desktop apps), the code is needed to support older browsers. This constraint limited the use of modern JavaScript features and required several workarounds.
On the other hand, Microsoft's sample implementation for NAA was written in TypeScript using modern libraries like MSAL.js v3. TypeScript’s static typing, combined with MSAL.js’s simplified token acquisition flow, made the new samples much cleaner and easier to follow — but also harder to integrate directly into our older codebase.
This meant that I couldn’t just plug and play the sample code — I had to bridge the gap between old and new paradigms while ensuring backward compatibility.
Optimizing the User Journey
“A user interface is like a joke. If you have to explain it, it’s not that good.” — Martin LeBlanc
Once the technical flow was in place, Abhishek pointed out that the user experience wasn’t quite there yet. Imagine the confusion when users suddenly saw pop-ups asking for SSO without any context! In collaboration with the Product and Design teams, we introduced:
Informative modals explaining the process, complete with Allow and Decline buttons.
A friendly CTA prompting users to try SSO again if they’d declined initially.
The Final Boss: Safari
After weeks of effort and thorough testing on various Browsers and the Outlook desktop app, we were ready for release. But on the day of the release, I tested it on Safari, and it did not work.
I reported the issue to Dimple, who made the hard call to revert the changes until we figured out the Safari issue. I was disheartened after all the effort, but this setback taught me a crucial lesson — Always test every scenario by stepping into the user’s shoes rather than relying solely on your developer instincts.
In Abhishek’s words — “Try to break things, if they don’t then we are good to go.”
“Everything happens for a reason.” It was fortunate that the issue surfaced before release, allowing us to uncover and fix potential flow problems before they became bigger challenges.
Conclusion
Migrating to NAA was much more than a technical upgrade — it was an adventure filled with learning, frustration, and growth. The entire journey taught me that legacy codebases are full of surprises and that effective collaboration among engineering, product, and design teams can turn a seemingly insurmountable challenge into a success story.
If you’re planning a similar migration, keep in mind:
Test across all browsers (Safari, in particular, can be unpredictable).
Embrace the quirks of legacy systems.
And remember, in the midst of endless Microsoft documentation and debugging sessions, Microsoft's documentation is your friend... eventually. 😉
Happy coding, and may your migrations be ever in your favor!