Next.js Discord

Discord Forum

MSAL clearHash() after redirect causing exception in Next.js 14 exported client app

Unanswered
TimTucker posted this in #help-forum
Open in Discord
Finding issues with the combination of MSAL-React + Next.js 14 when using redirect for logins.

Everything works if I run the application "live"

When I export the app as a client bundle, though, I'm seeing exceptions when MSAL processes the redirect.

From what it looks like:
- Initial page load is OK
- MSAL sees that the user needs to sign in
- MSAL redirects to a Microsoft page for sign in
- The Microsoft page redirects back, with data sent in the URL
- MSAL grabs the data out of the URL
- Next.js overrides window.history.replaceState
- MSAL has a clearHash() function that attempts to clear the "#" from the URL
- clearHash() makes a call to window.history.replaceState
- Next.js calls applyUrlFromHistoryPushReplace() from the overridden window.history.replaceState
- applyUrlFromHistoryPushReplace attempts to access window.history.state.__PRIVATE_NEXTJS_INTERNALS_TREE
- window.history.state is null at that point, so an exception gets thrown

Note that I'm passing a custom NavigationClient to the MSAL instance that uses the Next.js router for navigateInternal, but that doesn't appear to be getting called in this flow.

I haven't yet figured out why it works live, but not in the exported build -- I suspect it's a timing issue and in the live build either:
- MSAL makes the call to window.history.replaceState faster than Next.js can override it
- Next.js is able to set the value of window.history.state before MSAL attempts to call replaceState

Not sure if this is an MSAL bug or a Next.js bug.

It seems like this could potentially be addressed with either (or both):
- A null check on the Next.js side
- Using the Navigation client for updating the URL on the MSAL side (to enable everything that modifies the URL to go through the Next.js router)

2 Replies

The exception:
Cannot read properties of null (reading 'PRIVATE_NEXTJS_INTERNALS_TREE')

The relevant call stack:
at main-app-02669ec414a26910.js:1028:48
at
webpack_modules__.45060.exports.startTransition (main-app-02669ec414a26910.js:16861:9)
at applyUrlFromHistoryPushReplace (main-app-02669ec414a26910.js:1024:40)
at History.replaceState (main-app-02669ec414a26910.js:1058:17)
at clearHash (page-2720a79a295b2bcc.js:6199:31)
at RedirectClient.getRedirectResponse (page-2720a79a295b2bcc.js:10086:13)
at RedirectClient.handleRedirectPromise (page-2720a79a295b2bcc.js:9994:57)
at StandardController.handleRedirectPromise (page-2720a79a295b2bcc.js:10905:55)
at PublicClientApplication.handleRedirectPromise (page-2720a79a295b2bcc.js:2752:32)

(everything above clearHash is Next.js code / everything from clearHash and below is MSAL code)
Also tracking as an issue with MSAL:
https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/6851

From comments there, there was reference to being able to revert back to 14.0.4 as a workaround.


Confirmed locally:

This is definitely an issue with the new windowHistorySupport feature added in Next.js 14.0.5

Everything works fine if app-router.tsx has applyUrlFromHistoryPushReplace modified from:
window.history.state.__PRIVATE_NEXTJS_INTERNALS_TREE
to
window.history.state?.__PRIVATE_NEXTJS_INTERNALS_TREE

Pull request submitted:
https://github.com/vercel/next.js/pull/61395