You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Passing data from UserStorageProvider to token claim
#14359
I'm trying to get a better understanding of the best practices around persisting data and error handling when writing a custom UserStorageProvider and OIDCProtocolMapper.
At a high-level, the goal is to have the UserStorageProvider reach out to a backend service during authentication and gather user/request information. This data would then be passed to an OIDCProtocolMapper which would both add the data as a claim, or make additional backend calls. As these backend calls can produce errors, there would ideally be a mechanism in place to handle them in a user friendly way.
I've put together a basic demo of the approach I've taken so far, but the general process is as follows:
The UserStorageProvider's isValid call makes a request to the backend service grabbing additional information about the user and the request itself. For this example, it's just a single string. As isValid only returns a boolean, it seems the only mechanism to get information out is a KeycloakSession attribute. Example:
publicbooleanisValid(RealmModelrealm, UserModeluser, CredentialInputinput) {
// In order to simplify this example, doBackendServiceCall simply returns a// string which we'd like to act on later in the ProtocolMapper.StringbackendCallResult = doBackendServiceCall();
session.setAttribute("demo-backend-data-attribute", backendCallResult);
// Authenticate for a single user "user" with password "password"if (!supportsCredentialType(input.getType()) || !(inputinstanceofUserCredentialModel))
returnfalse;
varpassword = ((UserCredentialModel) input).getValue();
returnuser.getUsername() == "user" && password.equals("password");
}
Since KeycloakSession is per-request, the attribute is read from a replacement custom UsernamePasswordForm authenticator, and converted to a user session note via context.getAuthenticationSession().setUserSessionNote. Example:
publicvoidaction(AuthenticationFlowContextcontext) {
super.action(context);
// Convert keycloak session attribute to a user session note, so it will be accessible// from the ProtocolMapper later.varbackendCallResult = (String)context.getSession().getAttribute("demo-backend-data-attribute");
context.getAuthenticationSession().setUserSessionNote("demo-backend-data-note", backendCallResult);
}
Finally, with the data available throughout the whole user session, it is read from a OIDCProtocolMapper which maps the session note to a claim. I'm aware this can be done with a built-in mapper, however the data would potentially feed into further claims and backend calls. Example:
publicAccessTokentransformAccessToken(AccessTokentoken, ProtocolMapperModelmappingModel, KeycloakSessionkeycloakSession, UserSessionModeluserSession, ClientSessionContextclientSessionCtx) {
// Retrieve data from the UserStorageProvider's backend call.StringbackendCallResult = userSession.getNote("demo-backend-data-note");
token.getOtherClaims().put("demo-backend-data-1", backendCallResult);
// Do another mock call to the backend. In order to keep things simple,// the result here is a String as well.StringadditionalResult = doAdditionalBackendCall();
token.getOtherClaims().put("demo-backend-data-2", additionalResult);
setClaim(token, mappingModel, userSession, keycloakSession, clientSessionCtx);
returntoken;
}
This had lead to a couple of questions:
When working with a UserStorageProvider.isValid, is there a preferred method of getting user data out of the isValid method?
As it stands I'm using the KeycloakSession attributes, which seem less than ideal, as I need to then convert it to a user session note later. However, I don't see any other mechanism for getting data out of the method. Perhaps this is not the appropriate place for such backend calls?
Adding to that, when the backend call in isValid encounters an issue, what's the preferred method for passing additional error context (such as a message) back to the form?
Given that the UsernamePasswordForm is already being extended, it seems to follow that the message could be passed via the KeycloakSession attribute, and simply consumed immediately to provide context for the error.
Should a backend call encounter an error within the ProtocolMapper, are there any best practices to follow to report that failure back to the user?
Given when this call typically occurs, I'm not entirely sure what can be done. I'd be curious to know if there's any existing conventions to follow. Perhaps having backend calls within the mapper is incorrect to begin with?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hello,
I'm trying to get a better understanding of the best practices around persisting data and error handling when writing a custom
UserStorageProviderandOIDCProtocolMapper.At a high-level, the goal is to have the
UserStorageProviderreach out to a backend service during authentication and gather user/request information. This data would then be passed to anOIDCProtocolMapperwhich would both add the data as a claim, or make additional backend calls. As these backend calls can produce errors, there would ideally be a mechanism in place to handle them in a user friendly way.I've put together a basic demo of the approach I've taken so far, but the general process is as follows:
UserStorageProvider'sisValidcall makes a request to the backend service grabbing additional information about the user and the request itself. For this example, it's just a single string. AsisValidonly returns a boolean, it seems the only mechanism to get information out is aKeycloakSessionattribute. Example:KeycloakSessionis per-request, the attribute is read from a replacement customUsernamePasswordFormauthenticator, and converted to a user session note viacontext.getAuthenticationSession().setUserSessionNote. Example:OIDCProtocolMapperwhich maps the session note to a claim. I'm aware this can be done with a built-in mapper, however the data would potentially feed into further claims and backend calls. Example:This had lead to a couple of questions:
UserStorageProvider.isValid, is there a preferred method of getting user data out of theisValidmethod?As it stands I'm using the
KeycloakSessionattributes, which seem less than ideal, as I need to then convert it to a user session note later. However, I don't see any other mechanism for getting data out of the method. Perhaps this is not the appropriate place for such backend calls?isValidencounters an issue, what's the preferred method for passing additional error context (such as a message) back to the form?Given that the
UsernamePasswordFormis already being extended, it seems to follow that the message could be passed via theKeycloakSessionattribute, and simply consumed immediately to provide context for the error.ProtocolMapper, are there any best practices to follow to report that failure back to the user?Given when this call typically occurs, I'm not entirely sure what can be done. I'd be curious to know if there's any existing conventions to follow. Perhaps having backend calls within the mapper is incorrect to begin with?
Any recommendations are welcome.
Thanks
All reactions
Replies: 0 comments