Today I spent the day fixing three issues that had been sitting in Nortrip Toolbox, my B2B SaaS back-office for travel agencies. Nothing glamorous — security hardening, reliability fixes, and a bit of automation. Here is what got built.
Nortrip Toolbox was storing session data in localStorage. That means if a travel agent left their workstation unlocked, anyone could open the browser tab and land straight in the back-office. Not great for a tool that handles quotes, invoices, and client data.
Migrating to sessionStorage looks straightforward on paper. In practice, it is a cascade of changes: every token read and write needs to be updated, authentication hooks too, and tab-close behaviour has to be handled cleanly.
// Before — data persists even after browser close
localStorage.setItem("auth_token", token)
// After — scoped to the tab, cleared on close
sessionStorage.setItem("auth_token", token)
I added two extra mechanisms: a 2-hour inactivity timeout (an addEventListener on mousemove, keydown and click that resets a timer), and an immediate logout whenever the user navigates away from the /admin route. The session no longer survives outside the secured perimeter.
Microsoft Azure AD (via MSAL.js) issues OAuth tokens that expire. Until today, when a token expired during an active session, the user saw a cryptic error and had to reload the page manually. Not acceptable.
The real problem was twofold. First, an unhandled InteractionRequiredAuthError was silently crashing API calls. Second, a shared readyRef was getting poisoned: once flipped to false after an error, it never went back to true, blocking any subsequent refresh attempt.
// The catch that changes everything
try {
const result = await msalInstance.acquireTokenSilent(request)
return result.accessToken
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
// Clean re-auth popup, no visible error
const result = await msalInstance.acquireTokenPopup(request)
return result.accessToken
}
throw error
}
Now, when the token expires, a Microsoft popup opens automatically. The user re-authenticates in two clicks, and work continues without losing context. The readyRef was isolated per component to prevent contamination across the app.
Keewe is our currency management tool. Every month it generates PDF statements. Until today, someone downloaded them, renamed them, and manually dropped them into the right OneDrive folder. Three clicks minimum, times twelve months, times human error.
The automation I built works like this: the agent uploads the PDF via a button in Toolbox, a Next.js API route receives the file, sends the content to Claude AI (Anthropic) to extract the value_date, then builds the target OneDrive path:
NORTRIP/ADMINISTRATIF/Devises/KEEWE/{yyyy} Relevés Keewe/{yyyy}.{mm} Keewe/
Then Microsoft Graph API handles the upload:
await graphClient
.api(`/drives/${driveId}/root:/${targetPath}:/content`)
.put(fileBuffer)
Once the file is deposited, the UI shows a Validate button with a green cloud icon — a visual confirmation that everything is in order on the OneDrive side. No more doubt, no more manual verification.
None of these three items are spectacular to present. Nobody asks for a SaaS that handles token expiry gracefully. But this is exactly the kind of work that makes the difference between a tool you use with confidence and one you watch nervously from the corner of your eye.
If you are building a B2B back-office and wondering how to structure authentication, Microsoft integration, or document automation, I offer free audits — we look together at what is blocking you.
Prêt à automatiser votre business ?
Audit gratuit 1h — on identifie ensemble les 3 automatisations les plus rentables pour vous.
Réserver l'audit gratuit