I have a React application that uses @msal react
package. For some reason, when I don't use the application on my dev server for some time and then return to it later, e.g. a week or two later, and try to make a request in the webpage, the response will be a http error 401 unauthorized
.
When I do a hard refresh, the request will go through, but it is still using the same access token that was used on the first attempt after being idle.
I currently have no idea why it is doing this. I even copied the access token that was used the first time after being idle and returning a 401 Unauthorized in the Swagger Swash buckle for my backend and it works there also. I am using an ASP.NET Core Web API backend with the [Authorize]
attribute to protect my routes.
I am not sure if this could be the potential problem, but I do not think it is since as stated, the token works in the Swagger Swashbuckle.
EDIT Added my custom hook which generates a token and sets the state.
const useAccessToken = () => {
const { instance, accounts } = useMsal()
const [accessToken, setAccessToken] = useState('')
const getAccessToken = useCallback(async () => {
try {
const user = JSON.parse(localStorage.getItem('user'))
const response = await instance?.acquireTokenSilent({
account: accounts[0],
forceRefresh: true,
scopes:
user?.role === config.someUserRole
? [b2cOptions.scopes[0]]
: [entraOptions.scopes[1]],
})
setAccessToken(response.accessToken)
} catch (error) {
localStorage.clear()
instance?.logoutPopup({
mainWindowRedirectUri: loginRoute,
})
}
}, [accounts, envConfig, instance, setAccessToken])
useEffect(() => {
getAccessToken()
}, [accounts, getAccessToken, instance])
return accessToken
}
export default useAccessToken
Access token from Azure MSAL in React does not work on first request after idle time
MSAL caches tokens in memory or session/local storage. App is being idle for a long time, so MSAL tries to reuse the cached token, but the server rejects it for reasons like token expiration, backend policy.
Swagger works because it sends the token directly, without depending on MSAL's token cache or React state. This avoids any issues that may occur when MSAL reuses an outdated or invalid token after long idle periods.
The hard refresh forces MSAL to reset its internal state and request a new token so it is working without any issue.
Make sure to add the token in the API call and Use acquireTokenSilent()
with proper error handling, and set forceRefresh: true
to manually refresh the token if the app has been idle for a long time.
const tokenResponse = await msalInstance.acquireTokenSilent({
account: msalInstance.getAllAccounts()[0],
scopes: ["api://your-api-id/.default"]
forceRefresh: true
});
fetch("https://your-api.com/endpoint", {
method: "GET",
headers: {
Authorization: `Bearer ${tokenResponse.accessToken}`
}
});
These changes should help resolve the issues you're facing after idle sessions and ensure smooth authentication in your React app.