[keycloak-dev] Issue with concurrent SSO login to same client in more browser tabs

Marek Posolda mposolda at redhat.com
Mon Nov 19 05:45:36 EST 2018


Hi,

I've sent PR https://github.com/keycloak/keycloak/pull/5736 to fix the 
issue in subject (corresponding JIRAs are KEYCLOAK-7774 KEYCLOAK-8438). 
The cause is that once the user is authenticated in the browser and has 
userSession, there is just 1 clientSession per the userSession+client. 
So in case of concurrent SSO login in more browser tabs, there can be an 
issue that each tab is writing it's state to the same clientSession, 
which causes conflicts (especially attributes like nonce, scope or 
redirectUri can be possibly different for each tab and shouldn't be 
shared).

The possibility can be to revert back when we had more clientSessions 
per userSession+client. I think this is step back and has lots of other 
issues (memory consumption, more cluster and cross-dc writes, worse 
performance in general...). For the future, it will be rather ideal to 
remove clientSession entirely or reduce their size even more, as they 
will be needed for logout, but hopefully for nothing more.

So the other possibility is to move most of the state to the "code" 
parameter and to the refreshToken. Each browser tab has it's own "code" 
and it's own refreshToken. Problem with the "code" is, that it's used as 
query parameter in the URL and hence has limits for it's size. It seems 
ideal is still to stick with 2000 characters per URL. And when 
redirectUri itself will be part of the code, it can be problematic as we 
don't know how the redirectUri provided by users will be big.... 
Fortunately refreshToken doesn't have this issue as it needs to be 
always sent in the POST request.

So to solve the issue for "code", I've added an entry to the infinispan 
cache "actionTokens", which encapsulates needed state and it's supposed 
to be valid just for the very short time (between the 
AuthenticationResponse to the application and the time when application 
sends the code-to-token request) and it's lifespan corresponds to realm 
code lifespan (1 minute by default). In the code-to-token request, there 
is a call to "cache.remove" to remove the code. Infinispan caches 
(local, distributed and hotrod caches) fortunately guarantee that 
"remove(123)" is always successful just in 1 thread (Successful means 
that it returns previous state). So we still have guarantee for the 
single-use code.

Marek



More information about the keycloak-dev mailing list