The current algorithm for token renewal is to filter all servlet requests on any portal URL and to trigger a refresh token request as soon as the access token has expired and wait for the request token response to carry on with the filter chain. If the refresh token request fails, then the user's session will be terminated. However, this algorithm is likely to fail if the OpenID Provider has adopted a policy where Refresh Token can only be used once.
There is an almost certain probability that Liferay will manage simultaneous servlet requests from a client serving pages with resources (pictures, documents, XHR, CSS, JS...) through multiple threads. Many threads will go through the filter and filter the refresh token request before one thread will actually have received a response from the OpenID Provider. As a consequence, the second thread to hit the token endpoint will get an error and terminate the session.
With this enhancement, only one thread at a time will be able to request a refresh token. A possible answer is to implement a soft lock on the OIDC session object and to release it once a response has been received from the OpenId provider.
Link to a custom implementation: https://github.com/fabian-bouche-liferay/oidc-refresh (and it may be needed that to implement a more proper object to store the flag in the session object than the UserInfo object's claim that has been hijacked).
In order not to block the other threads, a suggestion is, the token renewal should be anticipated before the Access token actually expires, so that we can let other threads pass through the OIDC filter as long as their token haven't expired. For another reason detailed in the following ticket, token renewal anticipation is requested in another LPS:
- As an Instance Administrator, I want to be sure that the user session is not terminated during the refresh token process and so they don't need to grant authorization again.