Hello guys,
My use case is precisely as discussed by @larsf96 in a previous thread (persistent-custom-claims-in-access-token-when-using-refresh-tokens/111268). Wasn’t allowed to add the actual link–sorry about that.
@rueben.tiow partially answered (will-access-tokens-received-via-refresh-token-contain-the-custom-claims/131015) but this does not cover the use case mentioned by @larsf96:
[…] we will create an internal couplingID during the first token exchange and we want to store the couplingID in the access token and want to persist it even during refresh token exchanges.
Imagine the couplingID
is randomly generated during the first token exchange (e.g. converting the authorization code into access and refresh tokens) and set as a custom claim on the first access token. The goal is to keep setting the same couplingID
on all access tokens that are generated by the same refresh token. For this we need to store the couplingID
in the app metadata against some unique identifier (ideally the refresh token or its ID). However, I couldn’t find a unique identifier that remains the same across all the token exchanges performed with the same refresh token. I noticed that in post-login
there is event.refresh_token.id
which could acts as the unique identifier–however this is not available in the first token exchange which is when the couplingID
is generated… Therefore, there does not seem to be a way of persisting the couplingID
across token refreshes.
Simply running the same action without conditionals on each token exchange (as @rueben.tiow mentioned) is not an option as a different couplingID
would be generated for each access token–which defeats the goal.
This seems quite a big limitation as it prevents the API receiving requests authorized with access tokens generated by the same refresh token to be grouped together (via the couplingID
custom claim). Is there a way around it?
This is quite urgent for our company so please let me know 
Summary
This text will be hidden
Hi @massimoalbarello,
Thanks for your question.
As you discovered, the best approach is to use a post-login action to set the same couplingID
as a custom claim in the access token. Once it’s added, the custom claim will persist across every access token request, including the first one.
If you need a unique identifier to help you with saving the couplingID
in the app_metadata, you could try using the event.session.id
property.
Does that help?
Kind regards,
Rueben
Hello @rueben.tiow,
I’m logging event.session
every time the post-login action is executed. It seems that event.session
is defined when i call the /authorize
endpoint but every time I refresh the token it is undefined
…
Also, I need an id that is unique per user authorization. I noticed that if the user calls /authorize
multiple times without logging out and logging back in in between, event.session.id
stays the same in both authorizations, which is a problem as i cannot differentiate between the two.
If the refresh token id were available also when the authorization code is exchanged it would solve my problem but this is not the case unfortunately.
Is there another way?
I noticed that there is event.refresh_token.session_id
which I could use to map the oauth2-refresh-token
actions to the oidc-basic-profile
one where event.session.id
was first defined. However, it seems that in some refreshes event.refresh_token.session_id
is undefined
… Why is this the case?
Also, is it normal that the post-login
action is not triggered when the authorization code is converted into an access token? I only see it being fired for oidc-basic-profile
and oauth2-refresh-token
but weirdly not for oauth2-access-token
. Is this expected?
Thanks in advance
Hello @rueben.tiow, any ideas how else I could solve this problem?
Thanks
Hi @massimoalbarello,
Thanks for all the responses.
I noticed the same as well. During the initial login flow, the event.session.id
is defined, and the event.refresh_token.session_id
is undefined. Whereas, during a refresh token exchange, the opposite would happen, where the event.session.id
is undefined, and the event.refresh_token.session_id
is defined.
Knowing this, one option could be to save the event.session.id
from the initial login flow into the user’s app_metadata. Then, on refresh token exchange events, you can use the event.user.app_metadata.sessionID
property instead. This works because that property would always have the current session ID and is overwritten only when creating a new session.
Yes, this is totally normal. This is because the post-login action runs before it exchanges an authorization code for an access token. Therefore, the order of events looks like this: user logs in> post-login action > exchange authorization code for access token.
Let me know if you need help implementing this in a post-login action.
Kind regards,
Rueben
Hello again @rueben.tiow,
The problem with the session id is that it is not necessarily unique across different authorizations (if a user authorizes twice without logging out in between, both authorizations would get the same session id).
From what I found, the event.refresh_token.id
is the only value that can actually be used to distinguish two authorizations. Is there a way for me to access the event.refresh_token.id
during the oidc-basic-profile
action?
Alternatively, is there another action that can be triggered after exchange authorization code for access token
so that in there I might be able to both write a custom claim onto the access token and read the id of the refresh token?
Thanks again
Hi @massimoalbarello,
I completely understand.
As far as I know, this is not possible because the event.refresh_token.session_id
does not exist at the time of the original login. However, when you perform a refresh token exchange, this property will exist, and you can add it as a custom claim. This works because all access tokens issued from a refresh token exchange will include the same session_id, as long as the session remains active. This ensures that the tokens are tied to the same session.
Ultimately, there is no way to get that value in the initial login request and append it as a custom claim.
There are also no other actions that can trigger during an authorization code exchange for an access token. Only the post-login action trigger is the best match for this use case.
I am curious, do you have any code snippets of what you have tried so far?
Kind regards,
Rueben
Here is a snippet of my post-login action:
// HP: After an action for 'oidc-basic-profile' is triggered for a user,
// no second action for 'oidc-basic-profile' is triggered for the same user
// before the the 'oauth2-refresh-token' action for the first authorization is triggered.
// If this is not true, the 'connection_uuid' initially associated with the first authorization might then be associated to the second one.
let connection_uuid;
if (event.transaction.protocol === "oidc-basic-profile") {
let connections = event.user.app_metadata.connections || [];
console.log("Pre-login connections:", connections);
connection_uuid = uuidv4();
connections.push(connection_uuid);
api.user.setAppMetadata("connections", connections);
console.log("Post-login connections:", connections);
}
else if (event.transaction.protocol === "oauth2-refresh-token") {
const refresh_token_id = event.refresh_token.id;
if (event.user.app_metadata[refresh_token_id]) {
connection_uuid = event.user.app_metadata[refresh_token_id];
}
else {
let connections = event.user.app_metadata.connections;
console.log("Pre-refresh connections:", connections);
connection_uuid = connections.pop();
api.user.setAppMetadata("connections", connections);
console.log("Post-refresh connections:", connections);
api.user.setAppMetadata(refresh_token_id, connection_uuid);
}
}
if (connection_uuid) {
api.accessToken.setCustomClaim("fabric_connection_uuid", connection_uuid);
console.log("Set fabric_connection_uuid:", connection_uuid);
}
Basically, on oidc-basic-profile
i create a random connection_uuid
(what in this thread we have been calling couplingID
) and store it in the app metadata. On the first oauth2-refresh-token
i get the connection_uuid
and store it against the refresh_token_id
. From then on, all access tokens generated with that refresh token will have the same connection_uuid
as a custom claim.
This works well as long as the user does not create a second authorization before oauth2-refresh-token
of the first one is run. If that’s the case, a connection_uuid
initially assigned to an access token of the first authorization (during oidc-basic-profile
) might then get assigned to an access token of the second authorization.
Using event.session.id
to distinguish the two authorizations during oidc-basic-profile
might not work as they could have the same session id.
Isn’t this use case common?