It can happen that more requests are trying to update same userSession. This is the case for example when there are concurrent requests from same browser from multiple browser tabs.
There is a fix
KEYCLOAK-4821, which adds thread-safety to sessionEntity and fixes concurrency issues in local environment. However in cluster/cross-dc there are still possibilities for inconsistencies.
- User is authenticated in client "customer-portal". On Keycloak there is userSession, which has clients: ["customer-portal"]
- User goes to "http://localhost:8080/customer-portal". This may send backchannel request to Keycloak for refresh token. Assume this is request1 processed on cluster node1
- At the same time, user goes in another browser tab to "http://localhost:8080/product-portal" . This will trigger SSO login, which will add "product-portal" as another client to userSession. Assume this is request2 processed on cluster node2.
Now concurrent requests can be processed in this order:
- request1 on node1 reads userSession with clients: ["customer-portal"]
- request2 on node2 reads userSession with clients: ["customer-portal"]
- request2 finishes SSO login and adds another client to userSession. So there are: clients: ["customer-portal", "product-portal"]
- request2 commits the transaction and updates userSession in infinispan on node2.
- After that, request1 on node1 refreshes token and updates "lastSessionRefresh" on userSession on node2. Note that instance on node2 doesn't see latest update by request2 as it was read before the update! Hence the sessionEntity instance still has: clients: ["customer-portal"]
- request1 commits transaction. This will overwrite clients back to ["customer-portal"]. The evidence about "product-portal" client is lost -> FAIL!
I reproduced the issue with browser and debug session and I have a testcase (based on the email@example.com test for
KEYCLOAK-4827), which reproduces the concurrency issue in 2-node cluster environments.