Repository navigation
Updating identity on login #4618
Replies: 3 comments
|
Your reading of the merge behavior is correct, and it's worth pinning to the code that landed — plus there's one edge in it that's sharper than your examples suggest. The merge is in // merge merges the JSON messages in a and b. If a value is defined in both a and b, a wins.
func merge(a, b json.RawMessage) (identity.Traits, error) {
if len(a) == 0 || string(a) == "{}" {
return identity.Traits(b), nil // empty mapper output -> existing traits kept entirely
}
...
// values in aMap (src) win.
if err := mergo.Merge(&bMap, &aMap, mergo.Withoverride); err != nil { ... }where The sharper edge: your proposed workaround (explicitly emitting On whether merge-instead-of-replace is defensible: it's the conservative default for claims-derived traits. OIDC claims are situational — scopes can be dropped between logins, consent can lapse, a field that was present at registration can be absent at the next login. Replace-semantics would turn any such omission into data loss on a routine sign-in, which is destructive and not reviewable by the user. Merge makes every login a no-op-or-narrowing update instead. The cost is exactly your case: staleness for keys your IdP stops asserting. Practical patterns that work today:
If you do open the discussion-to-issue, the two concrete asks would be: (a) document that empty/omitted/null mapper output retains existing traits, and (b) decide whether |
This makes the merging even less intuitive, so even an explicit "null" value will be ignored. I've confirmed this in the code of the original code. 1: 2: It seems like there is no ergonomic way to update the identity after a login for people who are susceptible to the above mentioned issues. In case of point 1; The way that for example Kratos is used in a legacy infra in our case: Just as a disclaimer, I am not asking for practical solutions, there are a ton of things I can do to mitigate the issue, but I was wondering why the "merge" approach was chosen and if an "overwrite" flow was ever considered. In this scenario, it seems like low hanging fruit to support it, and let people just update their identity in a deterministic way via the mappers |
|
Since a webhook is out of scope for you right now, one middle path worth considering: the admin API ( If the merge-semantics analysis plus this route answers the question, marking it would help others landing here from PR #3922. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I followed #3922 for the better part of the issue. Recently the pull got closed because another way was implemented outside this pull request 4fcb299
When I review the code + the understanding I have of Kratos' internal workings; I noticed that the Metatadata and Traits are being merged instead of updated. The merging is done using Mergo, the Go library I see being used in the code. But this seems to do a deep merge, which in some scenarios can cause unwanted behaviour. Below I've sketched some example I can think of.
Example:
But in other cases, for example when omitting values in Jsonnet mappers (which I suppose is a general practice to reduce bloat in identities)
In this case "a" is not touched and keeps existing
This forces you to always explicitly set a property to null, which could be a breaking change for people relying on the value being omitted
For example in Zitadel I know that the user's roles is a nested map
They will omit the roles when you are removed from them
If someone just maps the above into the Identity metadata, then the result will be a that all the roles will accumulate over time
Here is a more concrete example
Have these cases been considered while implementing the feature, or am I just being paranoid 😓?
All reactions