Event Listener Provider synchronous execution?

Hey,

I would like to enrich the user profile with certain attributes before the information go to the client (via ID token, access token, or /userinfo). I implemented an even listener provider for the LOGIN event that achieves exactly that.

During some testing a colleague of mine noticed that there are circumstances where they do not get the updated token, but an old one. But on my end I can see that the changes were performed on the user profile. When they ask for the token again they receive an updated version.

That leads me to believe that the event listener provider is executed asynchronously and whether it works here is a matter of chance. Is that assumption correct? Can I make it synchronous/blocking, or is there another, better suited SPI?

EventListenerProvider implementations are executed as part of the same request transaction, so “synchronously”.

1 Like

Thank you for clarifying, I appreciate it! That drastically narrows down the issue for me.

Hey, sorry for bringing up this old thread. It took me a while to start investigating this issue properly.

Here is what I observe:

  1. client has an old auth token that contains certain role mapping
  2. client refreshes auth token
  3. event listener provider triggers (verified provider-side timestamp to match client-side timestamp)
  4. provider removes role from user: user.deleteRoleMapping(roleModel)
  5. client receives a new auth token (verified exp attr to be different from old auth token in 0.)
  6. new auth token still contains the removed role mapping
  7. client refreshes auth token again
  8. new auth token does not contain the role mapping (verified exp attr to be different from 4.)

This makes no sense to me. If the auth token is built after the event listener code triggered this should not happen. It shouldn’t require two refreshes to get the new user info into the token.

That leaves only 2 options:

  1. The auth token is built before the event listener had the chance to trigger
  2. The auth token builder code uses outdated user data in the same request transaction

Does someone know the exact order of events here, and maybe even a way to fix my situation?

Anyone? The way this provider behaves is worrying me, because it is security relevant to us. I would like to understand what is happening here.

Your steps sound right. Because the event listener is run in the same transaction, doesn’t mean order doesn’t matter. The new token is still getting minted (and response sent back from the request to the client) before the event listener runs.

That is very unfortunate, because we pick up security relevant information from another system when the user logs in. Can you think of a way to achieve what I’m trying to do?

I did already try to manually flush at the end of the event listener with little success:

session.getProvider(JpaConnectionProvider.class).getEntityManager().flush()

Admittedly, this was just a shot in the dark.

Why not build a custom Authenticator that checks the external system, and have that run in your Authentication flow?

1 Like

Oh right, this must necessarily run before the token is built…I’m going to try that.
Thank you for the advice :slight_smile:

But this wouldn’t work for when the client refreshes the token itself or when it contacts /userinfo, right?

The only authentication flow that comes to mind here is the client flow, but I strongly suspect that there is no user object available in that context.

I misunderstood you. I thought you only needed to check when the user logged in. You can write a token mapper, which should get run each time the token is built.

look at AbstractOIDCProtocolMapper, OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper

You can just override the 2 setClaim methods and do your fetching there.

1 Like