[Design Discussion] Account Linking and Attribute Syncing for External IDPs #3269
Replies: 2 comments 3 replies
|
Regarding Account Linking,
Currently in ThunderID, same federated user can have multiple local accounts in different OUs. For such cases, in the login flow, we can configure an executor to disambiguate the user. Given this, proceeding without linking for multiple matches is not the correct approach IMO. What if we link all matching local accounts to the same federated user in such cases? |
|
On Questions for Community Input,
For example There are two User A and B. A : username at External IDP is tom. name at Thunder local store is tom. A logs in. User type resolves to Student. So local store search is done for users with |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Related Feature Issue
#3032
Problem Summary
Today, account linking is based solely on the
subclaim of the ID token received in the OIDC flow. This works for JIT-provisioned users — they are linked to the local user viasubat provisioning time — but there is no way to link a federated identity to a pre-existing local user that was not JIT provisioned. We should be able to configure which attributes are used to match an incoming identity against local users.High-Level Approach
This proposal extends the IDP
attributeConfigurationmodel introduced in [1] with two new concerns: account linking (how an incoming federated identity resolves to an existing local user) and attribute syncing (how external attribute values are reconciled with the local account on subsequent logins).[1] #3157
Architecture Overview
{ "name": "Google", "type": "OIDC", "properties": [ "..." ], "attributeConfiguration": { "userTypeResolution": { "externalAttribute": "user_type", "valueMapping": { "employee": "Employee", "customer": "Person" }, "default": "Person" }, "accountLinking": { "attributes": [ { "externalAttribute": "email" } ] }, "syncPolicy": { "default": "overwrite", "attributes": [ { "externalAttribute": "given_name", "policy": "preserve-local" }, { "externalAttribute": "hd", "policy": "idp-profile" } ] }, "userTypeAttributeMappings": [ { "userType": "Person", "attributes": [ { "externalAttribute": "given_name", "localAttribute": "firstName" }, { "externalAttribute": "address.email", "localAttribute": "email" }, { "externalAttribute": "org_name", "localAttribute": "orgName" } ] } ] } }Account Linking
When no local user is found by subject identifier, the listed external attributes are used to look up an existing local user. The lookup semantics are:
userTypeAttributeMappingsfor the resolved user type.localAttributetargets are validated against the user type schema today.Each entry is an object in
attributesarray, rather than a bare string so per-attribute options can be added later without a breaking change (e.g., requireVerified: true to only link when the IDP asserts email_verified). Also which attribute shouldStoring linked identities
The same local user can be linked to multiple IDPs (e.g., Google and GitHub social logins). Instead of a single system attribute
{ "sub": "<subject-id>" }with the entity identifier indexed assub = <subject-id>, we store below under system attributes:{ "federatedIdentities": [ { "idpId": "<google-idp-id>", "subject": "<google-subject>" }, { "idpId": "<github-idp-id>", "subject": "<github-subject>" } ] }The entity identifier index becomes a composite key
<idp-id>:<subject>, so multiple subject identifiers stay indexed per user.Attribute Syncing
On every federated login after the first, mapped attribute values may have changed at the IDP. The
syncPolicyblock controls how those values are reconciled with the local account.defaultsets the overall policy; per-attribute entries override it.noneoverwritepreserve-localidp-profilefederatedIdentitiesentry) instead of the regular user attributes.IDP profile attributes
The subject identifier is already stored per IDP by default. The
idp-profilepolicy lets additional attributes be stored against the same per-IDP entry — useful for values that are meaningful only in the context of that IDP (e.g., the IDP-side org domain) and that should not collide across IDPs:{ "federatedIdentities": [ { "idpId": "<google-idp-id>", "subject": "<google-subject>", "domain": "abc.com" }, { "idpId": "<github-idp-id>", "subject": "<github-subject>", "domain": "abc.io" } ] }Attributes that should participate in the regular user profile (and be overwritten on sync) are recommended to be mapped to local attributes as usual;
idp-profileis for IDP-scoped data.API exposure
federatedIdentitiesis a system attribute. It is exposed only through dedicated APIs (e.g., listing a user's linked accounts, viewing linked-account details, unlinking) — never through the general user attribute APIs.Security Considerations
email_verified); otherwise an attacker could set a victim's email on their own IDP account and get linked to the victim's local account.Questions for Community Input
userTypeResolutionresolves to — reject, or link anyway?unlinkbe self-service via user APIs, admin-only, or different API?All reactions