Hi folks, I have a really interesting question: I'...
# ory-selfhosting
w
Hi folks, I have a really interesting question: I'm looking into validating the SSO email (coming from Google, Apple, etc.) to ensure that it matches the identity email. The goal is to prevent SSO linking if the identity email and SSO email differ: Question: How can we retrieve and store the newly linked OIDC email after linking an SSO account via settings flow? We are using ORY Kratos (v1.2.1, self-hosted) and allow users to link additional OIDC providers (e.g., Google) via the settings flow. Our use case: • We'd like to retrieve the email from the newly linked OIDC account (from
id_token
or similar) and store it in
identity.metadata_public
or
metadata_admin
. • This is necessary to validate or audit which account was linked and to prevent multiple unrelated emails being linked (e.g.,
<mailto:testMain@gmail.com|testMain@gmail.com>
+
<mailto:testOther@gmail.com|testOther@gmail.com>
). What we've tried: • Using a Jsonnet mapper: seems to only apply during initial registration, not during linking or login. -> gh issue https://github.com/ory/kratos/issues/2898 • Using post-settings and post-login webhooks: they do not include OIDC claims or identifiers of the newly linked provider. Is there any way — via Jsonnet, webhook, or something else — to get the new OIDC email (from
id_token
)
during linking, and store or validate it? We’re open to any workaround or best practice — even fetching claims via Admin API if that's required. Thanks in advance!
Extra info: Currently, if a user links multiple OIDC accounts with different emails (e.g.,
<mailto:testMain@gmail.com|testMain@gmail.com>
and
<mailto:testOther@gmail.com|testOther@gmail.com>
) to the same Kratos identity, unlinking one of them via the settings flow results in a 500 Internal Server Error from Kratos. This seems to happen when Kratos cannot resolve which OIDC credential to remove or due to inconsistency in internal state
b
This seems like a bug somewhere. By design, Kratos doesn't use the email for anything related to the OIDC, because of issues like this, and because emails addresses can be changed on the provider. So instead, Kratos uses the OAuth2
sub
claim, to uniquely identify the external account.
if a user links multiple OIDC accounts with different emails
Could you expand on how this would happen in your setup? Once a user has linked an account at a defined OIDC provider to a Kratos identity, Kratos normally doesn't allow linking another account at the same provider. So I wonder if this might be the root cause?
w
Thanks Jonas! Sure, I can clarify our flow: In our setup, a user can link an account via the login flow, even without an active Kratos session. This is possible if the email from the OIDC provider matches the email stored in the identity's traits — so Kratos links it automatically (after password verification) based on that match. However, in the settings flow, when a user is already logged in and links an OIDC provider for the first time, Kratos allows them to link any OIDC account, regardless of whether the email matches their current identity’s traits. This effectively results in multiple unrelated OIDC accounts being linked to a single Kratos identity (settings flow first, then another linking via login flow) Then comes the real issue: If the user later logs in again via the original OIDC account (used in the login flow), Kratos accepts it, and the identity ends up having two OIDC credentials (with different emails under the hood, the links actually visible in public.identity_credentials table and i can confirm that in my case users has multiple oidc accounts under same provider). Now, if the user tries to unlink one of those providers via the settings flow — Kratos returns a
500 Internal Server Error
. We've confirmed this is due to Kratos not being able to resolve which credential to unlink internally (or trying to unlink the wrong one)
Here is the values in
public.identity_credentials.config
Copy code
{
  "providers": [
    {
      "subject": "115953378442588631813",
      "provider": "google-external",
      "initial_id_token": "someToken",
      "initial_access_token": "someToken",
      "initial_refresh_token": ""
    },
    {
      "subject": "102606360791501818151",
      "provider": "google-external",
      "initial_id_token": "someToken",
      "initial_access_token": "someToken",
      "initial_refresh_token": ""
    }
  ]
}
I just bumped our Kratos version to v1.3.1, and the 500 error during the unlinking process is gone — now all OIDC accounts unlink correctly via the settings flow. However, the core issue still persists: users are still able to link multiple unrelated OIDC accounts (with different emails)
b
The settings flow shouldn't return the
link
nodes for providers that are already linked. Did you build your own UI here, that just calls the API with the provider if the user clicks on the button?
w
Yep, we do this via api
the flow: first we link oidc account via settings flow -> then another one in login flow
login flow don't have user's session, that's why
link
node is persists all the time. But if we do: login flow first -> the settings will not give us link node for this provider (like you mentioned, since it's already linked)
b
But if we do: login flow first -> the settings will not give us link node for this provider (like you mentioned, since it's already linked)
Yea that's the intended flow. I am not sure what's happening during your login flow, but I would recommend that in your settings flow implementation you make sure that the user can't link the same provider again.
🙌 1
w
Once again to clarify, it's issue with login flow only: If a user logs in with an OIDC account (e.g. Google) and the email matches their identity email, Kratos links it — even if another Google account was already linked before (via settings flow). In the settings flow, this doesn't happen because Kratos hides already linked providers — the problem is specific to login flow without session