ory / network

Ory runs a global end-to-end security infrastructure for humans, robots, and servers. We build and use open source software.
Apache License 2.0
81 stars 6 forks source link

Can't use metadata fields from multiple social sign-in providers #164

Open dotubutis opened 2 years ago

dotubutis commented 2 years ago

Preflight checklist

Describe the bug

I'm trying to add different metadata_admin field mappings from different social sign-in providers. Only the fields provided by the first provider that is linked (by the end-user) persist. Is this expected behaviour, and, if so, is there a workaround?

Is there a way to populate fields from other providers, alongside the first one that is linked?

Reproducing the bug

1) User links Github as social login in the self-service UI 2) Then links Discord. 3) admin/identities/{id} endpoint returns only metadata fields provided by Github for the given user.

If first two steps are reversed, only Discord fields persist.

Relevant log output

{
  "id": "e4477736-7129-487c-a737-984a3552b8ea",
  "credentials": {
    "oidc": {
      "type": "oidc",
      "identifiers": [
        "discord:*********",
        "github:******"
      ],
      "version": 0,
      "created_at": "2022-09-28T14:28:09.934526Z",
      "updated_at": "2022-09-28T14:28:50.394822Z"
    },
    "password": {
      ...
    },
    "webauthn": {
      ...
    }
  },
  "schema_id": "f17ab650e6caa0b4210e08c9b057fcbf9bc30f3ed270dea04e3048ada6295f746141bf1ce1ed60b633c874db2ea0e65a1524575a00fb579ef0c3f156587ffbb3",
  "schema_url": "https://****.projects.oryapis.com/schemas/ZjE3YWI2NTBlNmNhYTBiNDIxMGUwOGM5YjA1N2ZjYmY5YmMzMGYzZWQyNzBkZWEwNGUzMDQ4YWRhNjI5NWY3NDYxNDFiZjFjZTFlZDYwYjYzM2M4NzRkYjJlYTBlNjVhMTUyNDU3NWEwMGZiNTc5ZWYwYzNmMTU2NTg3ZmZiYjM",
  "state": "active",
  "state_changed_at": "2022-09-28T14:28:09.813677Z",
  "traits": {
    ...
  },
  "verifiable_addresses": [
    {
      ...
    }
  ],
  "recovery_addresses": [
    ...
  ],
  "metadata_public": null,
  "metadata_admin": {
    "github_avatar_url": "https://avatars.githubusercontent.com/u/****?v=4",
    "github_profile_url": "https://github.com/****"
  },
  "created_at": "2022-09-28T14:28:09.837233Z",
  "updated_at": "2022-09-28T14:28:09.837233Z"
}

Relevant configuration

{
  "$id": "https://schemas.ory.sh/presets/kratos/identity.email.schema.json",
  "title": "Person",
  "type": "object",
  "properties": {
    "traits": {
      ...
    },
    "metadata_admin": {
      "type": "object",
      "properties": {
        "discord_name": {
          "type": "string"
        },
        "github_profile_url": {
          "type": "string"
        },
        "github_avatar_url": {
          "type": "string"
        }
      }
    }
  }
}

Version

Latest

On which operating system are you observing this issue?

Ory Cloud

In which environment are you deploying?

Ory Cloud

Additional Context

Github jsonnet mapping

local claims = {
  email_verified: false,
} + std.extVar('claims');
{
  identity: {
    traits: {
      [if 'email' in claims && claims.email_verified then 'email' else null]: claims.email,
    },
    metadata_admin: {
      github_profile_url: claims.profile,
      github_avatar_url: claims.picture
    },
  },
}

Discord jsonnet mapping

local claims = {
  email_verified: false,
} + std.extVar('claims');

{
  identity: {
    traits: {
      [if 'email' in claims && claims.email_verified then 'email' else null]: claims.email,
    },
    metadata_admin: {  
        discord_name: claims.name
      },
  },
}
aeneasr commented 2 years ago

This is a great question and your analysis is correct. The OIDC data from other social sign in providers are not synched during the account linking flow, they are only set up once during registration. I also definitely understand the use case why this is useful.

One problem here is that a new account linking process should usually not override the existing user's name (as they probably have set it up correctly already) or other data that should be left untouched. One idea could be to pass the existing identity to set.extVar(identity).

dotubutis commented 2 years ago

Thanks for the clarification! Could you elaborate on the suggested idea, not sure how that would work.

aeneasr commented 2 years ago

I guess something like this:

local claims = {
  email_verified: false,
} + std.extVar('claims');
local identity = std.extVar('identity')

{
  identity: {
    traits: identity.traits
    metadata_admin: identity.metadata_admin + {  
        discord_name: claims.name,
    },
  },
}
dotubutis commented 2 years ago

Thanks. If I understand correctly, in the current implementation this is not supposed to work bc, as you said, OIDC provider data is only set up once during the registration.

Is there any approach currently available for fetching OIDC data from social providers during the linking process, not the registration process?