> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-automated-translations-update.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Lier des comptes d’utilisateur

> Découvrez comment lier des comptes d’utilisateur issus de différents fournisseurs d’identité, afin que vos utilisateurs puissent s’authentifier avec n’importe lequel de leurs comptes et être reconnus par votre application.

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASQUÉ*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

<Card title="La disponibilité varie selon votre plan Auth0">
  La disponibilité de cette fonctionnalité dépend à la fois de votre mise en œuvre de connexion et de votre plan Auth0 ou de votre entente personnalisée. Pour en savoir plus, consultez [Tarification](https://auth0.com/pricing).
</Card>

Vous pouvez lier des comptes d’utilisateur de différentes façons :

* Action avec application externe de liaison
* Auth0 <Tooltip tip="Management API : un produit qui permet aux clients d’effectuer des tâches administratives." cta="Voir le glossaire" href="/docs/fr-ca/glossary?term=Management+API">Management API</Tooltip>
* bibliothèque auth0.js

<h2 id="action-with-external-linking-application">
  Action avec une application externe de liaison
</h2>

Vous pouvez utiliser une Action avec une application externe de liaison pour lier des comptes d’utilisateur au moyen de la Management API.

<Warning>
  **Auth0 ne passe pas automatiquement au bon** **utilisateur principal** après la liaison de comptes; ce changement doit donc être effectué dans le code Actions après une liaison de comptes réussie.

  **Chaque liaison manuelle de comptes devrait inviter l’utilisateur à saisir ses informations d’identification**. Votre tenant devrait exiger l’authentification des deux comptes avant que la liaison ait lieu afin d’éviter que des acteurs malveillants accèdent à des comptes d’utilisateur légitimes.
</Warning>

Les étapes suivantes illustrent un exemple de mise en œuvre :

1. L’Action identifie les comptes d’utilisateur potentiellement à lier (s’ils existent).

2. L’Action redirige l’utilisateur vers une application externe de liaison avec une charge utile de jeton contenant des identités d’utilisateur candidates :

   ```json theme={null}
   {
     "current_identity": {
       "user_id": event.user.user_id,
       "provider": event.connection.strategy,
       "connection": event.connection.name
     },
     "candidate_identities": [
       {
         "user_id": USER_ID_1,
         "provider": PROVIDER_1,
         "connection": CONNECTION_1
       },
       {
         "user_id": USER_ID_2,
         "provider": PROVIDER_2,
         "connection": CONNECTION_2
       },
       ...
     ]
   }
   ```

3. L’application externe de liaison invite l’utilisateur à s’authentifier à l’aide des informations d’identification du compte qu’il souhaite lier.

4. L’application externe de liaison redirige l’utilisateur vers l’Action avec une charge utile de jeton contenant les identités d’utilisateur principale et secondaire :

   ```json theme={null}
   {
     "primary_identity": {
       "user_id": PRIMARY_USER_ID,
       "provider": PRIMARY_PROVIDER_STRATEGY,
       "connection": PRIMARY_CONNECTION_NAME,
     },
     "secondary_identity": {
       "user_id": SECONDARY_USER_ID,
       "provider": SECONDARY_PROVIDER_STRATEGY,
       "connection": SECONDARY_CONNECTION_NAME,
     }
   }
   ```

5. L’Action valide l’authenticité et le contenu du jeton.

6. L’Action envoie une requête à la Management API pour lier les comptes selon les résultats de l’application externe de liaison.

7. L’Action passe à l’utilisateur principal s’il ne correspond pas à `event.user.user_id`.

<h2 id="example-account-linking-action">
  Exemple : Action de liaison de comptes
</h2>

```javascript lines expandable theme={null}
const { ManagementClient, AuthenticationClient } = require('auth0');

    /**
     * Action de liaison de comptes Auth0 - Version de production
     *
     * Dépendance requise : auth0@5.3.1
     *
     * Cette Action détecte les utilisateurs ayant des comptes en double (même adresse courriel vérifiée)
     * et les redirige vers un service externe pour gérer la liaison de comptes.
     */

    const ACCOUNT_LINKING_TIMESTAMP_KEY = 'account_linking_timestamp';
    const TTL_LEEWAY_FACTOR = 0.2;
    const PROPERTIES_TO_COMPLETE = ['given_name', 'family_name', 'name'];

    /**
     * Obtenir le jeton d'accès de la Management API avec mise en cache
     */
    const getManagementAccessToken = async (event, api) => {
      const cacheKey = `mgmt-api-token-${event.secrets.MANAGEMENT_API_CLIENT_ID}`;
      const cached = api.cache.get(cacheKey);

      if (cached && cached.value) {
        return cached.value;
      }

      const auth = new AuthenticationClient({
        domain: event.secrets.MANAGEMENT_API_DOMAIN,
        clientId: event.secrets.MANAGEMENT_API_CLIENT_ID,
        clientSecret: event.secrets.MANAGEMENT_API_CLIENT_SECRET
      });

      const response = await auth.oauth.clientCredentialsGrant({
        audience: `https://${event.secrets.MANAGEMENT_API_DOMAIN}/api/v2/`
      });

      
      const accessToken = response.access_token || response.data?.access_token;
      const expiresIn = response.expires_in || response.data?.expires_in;

      if (accessToken && typeof accessToken === 'string') {
        api.cache.set(cacheKey, accessToken, {
          ttl: expiresIn - expiresIn * TTL_LEEWAY_FACTOR
        });
      }

      return accessToken;
    };

    /**
     * Obtenir les utilisateurs ayant la même adresse courriel vérifiée
     */
    const getUsersWithSameEmail = async (event, api) => {
      const accessToken = await getManagementAccessToken(event, api);
      const management = new ManagementClient({
        domain: event.secrets.MANAGEMENT_API_DOMAIN,
        token: accessToken
      });

      
      const users = await management.users.listUsersByEmail({
        email: event.user.email
      });

      return users;
    };

    /**
     * Filtrer et mapper les identités candidates avec adresse courriel vérifiée
     */
    const getCandidateIdentitiesWithVerifiedEmail = (event, candidateUsers) => {
      return candidateUsers
        .filter((user) => user.user_id !== event.user.user_id && user.email_verified === true)
        .filter((user) => user.identities && user.identities.length > 0)
        .map((user) => ({
          user_id: user.user_id,
          provider: user.identities[0].provider,
          connection: user.identities[0].connection
        }));
    };

    /**
     * Lier les comptes à l'aide de la Management API
     * Lie l'identité secondaire À l'identité principale
     */
    const linkAccounts = async (event, primaryIdentity, secondaryIdentity) => {
      const accessToken = await getManagementAccessToken(event, { cache: { get: () => null, set: () => {} } });

      // Extraire la partie ID après le | pour l'API
      const idParts = secondaryIdentity.user_id.split('|');
      const userId = idParts.length > 1 ? idParts[1] : secondaryIdentity.user_id;

      const url = `https://${event.secrets.MANAGEMENT_API_DOMAIN}/api/v2/users/${encodeURIComponent(primaryIdentity.user_id)}/identities`;

      const body = {
        provider: secondaryIdentity.provider,
        user_id: userId
      };

      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(body)
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Link API error: ${response.status} - ${errorText}`);
      }

      return await response.json();
    };

    /**
     * Compléter les propriétés de profil manquantes à partir des identités liées
     */
    const completeProperties = (event, api) => {
      for (const property of PROPERTIES_TO_COMPLETE) {
        if (!event.user[property]) {
          for (const identity of event.user.identities) {
            if (identity.profileData && identity.profileData[property]) {
              api.idToken.setCustomClaim(property, identity.profileData[property]);
              break;
            }
          }
        }
      }
    };

    /**
     * onExecutePostLogin - Détecter les comptes en double et rediriger vers le service de liaison
     */
    exports.onExecutePostLogin = async (event, api) => {
      // Valider la configuration
      if (
        !event.secrets.MANAGEMENT_API_DOMAIN ||
        !event.secrets.MANAGEMENT_API_CLIENT_ID ||
        !event.secrets.MANAGEMENT_API_CLIENT_SECRET ||
        !event.secrets.SESSION_TOKEN_SHARED_SECRET ||
        !event.secrets.ACCOUNT_LINKING_SERVICE_URL
      ) {
        console.log('Missing required configuration - skipping account linking');
        return;
      }
      // Nous ne traiterons pas les utilisateurs pour la liaison de comptes tant qu'ils n'auront pas vérifié leur adresse courriel.
      // Nous pourrions envisager de rejeter les connexions ici ou de rediriger les utilisateurs vers un outil externe pour
      // rappeler à l'utilisateur de confirmer son adresse courriel avant de continuer.
      //
      // Dans cet exemple, nous ne traiterons simplement pas les utilisateurs à moins que leur courriel ne soit vérifié.
      if (!event.user.email_verified) {
        return;
      }

      // Ignorer si déjà traité
      if (event.user.app_metadata && event.user.app_metadata[ACCOUNT_LINKING_TIMESTAMP_KEY]) {
        completeProperties(event, api);
        return;
      }

      try {
        // Trouver les utilisateurs ayant le même courriel
        const candidateUsers = await getUsersWithSameEmail(event, api);

        if (!Array.isArray(candidateUsers) || candidateUsers.length === 0) {
          return;
        }

        // Filtrer pour les courriels vérifiés
        const candidateIdentities = getCandidateIdentitiesWithVerifiedEmail(event, candidateUsers);

        if (candidateIdentities.length === 0) {
          return;
        }

        // Créer le jeton de session
        const sessionToken = api.redirect.encodeToken({
          payload: {
            current_identity: {
              user_id: event.user.user_id,
              provider: event.connection.strategy,
              connection: event.connection.name
            },
            candidate_identities: candidateIdentities,
            email: event.user.email,
            continue_url: `https://${event.request.hostname}/continue`
          },
          secret: event.secrets.SESSION_TOKEN_SHARED_SECRET,
          expiresInSeconds: 120
        });

        // Rediriger vers le service de liaison
        api.redirect.sendUserTo(event.secrets.ACCOUNT_LINKING_SERVICE_URL, {
          query: {
            session_token: sessionToken
          }
        });

      } catch (err) {
        console.error('Account linking error:', err.message);
        // Ne pas bloquer la connexion en cas d'erreur
      }
    };

    /**
     * onContinuePostLogin - Traiter la décision de liaison de l'utilisateur
     */
    exports.onContinuePostLogin = async (event, api) => {
      try {
        // Valider le jeton de réponse
        const { primary_identity: primaryIdentity, secondary_identity: secondaryIdentity } = api.redirect.validateToken({
          secret: event.secrets.SESSION_TOKEN_SHARED_SECRET,
          tokenParameterName: 'session_token'
        });

        if (!primaryIdentity || !secondaryIdentity) {
          // L'utilisateur a annulé - continuer sans liaison
          return;
        }

        const currentUserId = event.user.user_id;

        // CRITIQUE : Basculer vers l'utilisateur principal AVANT la liaison
        // Cela évite l'erreur « Unable to construct login user »
        if (primaryIdentity.user_id !== currentUserId) {
          api.authentication.setPrimaryUser(primaryIdentity.user_id);
        }

        // Lier le compte secondaire
        const linkedIdentities = await linkAccounts(event, primaryIdentity, secondaryIdentity);

        if (linkedIdentities && linkedIdentities.length > 0) {
          // Marquer comme traité
          api.user.setAppMetadata(ACCOUNT_LINKING_TIMESTAMP_KEY, Date.now());
          completeProperties(event, api);
        } else {
          api.access.deny('Account linking failed');
        }
      } catch (err) {
        console.error('onContinuePostLogin error:', err.message);
        api.access.deny('Account linking error: ' + err.message);
      }
    };
```

<h2 id="management-api">
  Management API
</h2>

Vous pouvez utiliser le endpoint [Lier un compte d’utilisateur](/docs/fr-ca/api/management/v2/users/post-identities) de la Management API de deux façons :

* Liaison de comptes côté client initiée par l’utilisateur à l’aide de <Tooltip tip="Jeton d’accès : information d’identification d’autorisation, sous la forme d’une chaîne opaque ou d’un JWT, utilisée pour accéder à une API." cta="Voir le glossaire" href="/docs/fr-ca/glossary?term=access+tokens">jetons d’accès</Tooltip> avec la portée `update:current_user_identities`.
* Liaison de comptes côté serveur à l’aide de jetons d’accès avec la portée `update:users`.

<h3 id="user-initiated-client-side-account-linking">
  Liaison de comptes côté client initiée par l’utilisateur
</h3>

Pour la liaison de comptes côté client initiée par l’utilisateur, il vous faut un jeton d’accès qui contient les éléments suivants dans la charge utile :

* la portée `update:current_user_identites`
* le `user_id` du compte principal dans l’URL
* <Tooltip tip="Jeton d’identité : jeton destiné au client lui-même plutôt qu’à l’accès à une ressource." cta="Voir le glossaire" href="/docs/fr-ca/glossary?term=ID+token">jeton d’identité</Tooltip> du compte secondaire, signé avec RS256 et comportant une revendication `aud` qui identifie le client et correspond à la valeur de la revendication `azp` du jeton d’accès utilisé pour la demande.

Un jeton d’accès qui contient la portée `update:current_user_identities` ne peut être utilisé que pour mettre à jour les renseignements de l’utilisateur actuellement connecté. Cette méthode convient donc aux scénarios où l’utilisateur lance le processus de liaison.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">Vous utilisez Auth0 CLI? Si ce n’est pas déjà fait, [configurez et authentifiez votre session CLI](/docs/fr-ca/deploy-monitor/auth0-cli) avant d’exécuter cette commande.</Callout>

<AuthCodeGroup>
  ```bash Auth0 CLI theme={null}
  auth0 api post "users/PRIMARY_ACCOUNT_USER_ID/identities" \
    --data '{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}'
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities' \
    --header 'authorization: Bearer MANAGEMENT_API_ACCESS_TOKEN' \
    --header 'content-type: application/json' \
    --data '{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities");
  var request = new RestRequest(Method.POST);
  request.AddHeader("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN");
  request.AddHeader("content-type", "application/json");
  request.AddParameter("application/json", "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
      "fmt"
      "strings"
      "net/http"
      "io/ioutil"
  )

  func main() {
      url := "https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities"
      payload := strings.NewReader("{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}")

      req, _ := http.NewRequest("POST", url, payload)
      req.Header.Add("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN")
      req.Header.Add("content-type", "application/json")

      res, _ := http.DefaultClient.Do(req)
      defer res.Body.Close()
      body, _ := ioutil.ReadAll(res.Body)

      fmt.Println(res)
      fmt.Println(string(body))
  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.post("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities")
    .header("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN")
    .header("content-type", "application/json")
    .body("{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'POST',
    url: 'https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities',
    headers: {
      authorization: 'Bearer MANAGEMENT_API_ACCESS_TOKEN',
      'content-type': 'application/json'
    },
    data: {link_with: 'SECONDARY_ACCOUNT_ID_TOKEN'}
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MANAGEMENT_API_ACCESS_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  payload = "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}"

  headers = {
      'authorization': "Bearer MANAGEMENT_API_ACCESS_TOKEN",
      'content-type': "application/json"
      }

  conn.request("POST", "/{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  request = Net::HTTP::Post.new(url)
  request["authorization"] = 'Bearer MANAGEMENT_API_ACCESS_TOKEN'
  request["content-type"] = 'application/json'
  request.body = "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}"

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

<h3 id="server-side-account-linking">
  Liaison de comptes côté serveur
</h3>

Pour la liaison de comptes côté serveur, vous avez besoin d’un jeton d’accès qui contient les éléments suivants dans la charge utile :

* portée `update:users`
* `user_id` du compte principal dans l’URL
* `user_id` du compte secondaire
* jeton d’identité du compte secondaire signé avec RS256 et comprenant une revendication `aud` qui identifie le client et dont la valeur correspond à celle de la revendication `azp` du jeton d’accès à l’origine de la requête.

Les jetons d’accès qui contiennent la portée `update:users` peuvent servir à mettre à jour les renseignements de n’importe quel utilisateur. Par conséquent, cette méthode est réservée au code côté serveur.

<AuthCodeGroup>
  ```bash Auth0 CLI theme={null}
  auth0 api post "users/PRIMARY_ACCOUNT_USER_ID/identities" \
    --data '{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}'
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities' \
    --header 'authorization: Bearer MANAGEMENT_API_ACCESS_TOKEN' \
    --header 'content-type: application/json' \
    --data '{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities");
  var request = new RestRequest(Method.POST);
  request.AddHeader("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN");
  request.AddHeader("content-type", "application/json");
  request.AddParameter("application/json", "{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
      "fmt"
      "strings"
      "net/http"
      "io/ioutil"
  )

  func main() {

      url := "https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities"

      payload := strings.NewReader("{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}")

      req, _ := http.NewRequest("POST", url, payload)

      req.Header.Add("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN")
      req.Header.Add("content-type", "application/json")

      res, _ := http.DefaultClient.Do(req)

      defer res.Body.Close()
      body, _ := ioutil.ReadAll(res.Body)

      fmt.Println(res)
      fmt.Println(string(body))

  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.post("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities")
    .header("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN")
    .header("content-type", "application/json")
    .body("{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'POST',
    url: 'https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities',
    headers: {
      authorization: 'Bearer MANAGEMENT_API_ACCESS_TOKEN',
      'content-type': 'application/json'
    },
    data: {provider: 'SECONDARY_ACCOUNT_PROVIDER', user_id: 'SECONDARY_ACCOUNT_USER_ID'}
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => "{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MANAGEMENT_API_ACCESS_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  payload = "{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}"

  headers = {
      'authorization': "Bearer MANAGEMENT_API_ACCESS_TOKEN",
      'content-type': "application/json"
      }

  conn.request("POST", "/{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  request = Net::HTTP::Post.new(url)
  request["authorization"] = 'Bearer MANAGEMENT_API_ACCESS_TOKEN'
  request["content-type"] = 'application/json'
  request.body = "{"provider":"SECONDARY_ACCOUNT_PROVIDER", "user_id": "SECONDARY_ACCOUNT_USER_ID"}"

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

Le `user_id` et le `provider` du compte d’utilisateur secondaire peuvent être déduits à partir de son identifiant unique. Par exemple, pour l’identifiant `google-oauth2|108091299999329986433` :

* `provider` est `google-oauth2`
* `user_id` est `108091299999329986433`

Vous pouvez aussi envoyer le jeton d’identité du compte secondaire au lieu du `provider` et du `user_id` :

<AuthCodeGroup>
  ```bash Auth0 CLI theme={null}
  auth0 api post "users/PRIMARY_ACCOUNT_USER_ID/identities" \
    --data '{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}'
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities' \
    --header 'authorization: Bearer MANAGEMENT_API_ACCESS_TOKEN' \
    --header 'content-type: application/json' \
    --data '{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities");
  var request = new RestRequest(Method.POST);
  request.AddHeader("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN");
  request.AddHeader("content-type", "application/json");
  request.AddParameter("application/json", "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
      "fmt"
      "strings"
      "net/http"
      "io/ioutil"
  )

  func main() {
      url := "https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities"
      payload := strings.NewReader("{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}")

      req, _ := http.NewRequest("POST", url, payload)
      req.Header.Add("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN")
      req.Header.Add("content-type", "application/json")

      res, _ := http.DefaultClient.Do(req)
      defer res.Body.Close()
      body, _ := ioutil.ReadAll(res.Body)

      fmt.Println(res)
      fmt.Println(string(body))
  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.post("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities")
    .header("authorization", "Bearer MANAGEMENT_API_ACCESS_TOKEN")
    .header("content-type", "application/json")
    .body("{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'POST',
    url: 'https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities',
    headers: {
      authorization: 'Bearer MANAGEMENT_API_ACCESS_TOKEN',
      'content-type': 'application/json'
    },
    data: {link_with: 'SECONDARY_ACCOUNT_ID_TOKEN'}
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MANAGEMENT_API_ACCESS_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  payload = "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}"

  headers = {
      'authorization': "Bearer MANAGEMENT_API_ACCESS_TOKEN",
      'content-type': "application/json"
      }

  conn.request("POST", "/{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/users/PRIMARY_ACCOUNT_USER_ID/identities")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  request = Net::HTTP::Post.new(url)
  request["authorization"] = 'Bearer MANAGEMENT_API_ACCESS_TOKEN'
  request["content-type"] = 'application/json'
  request.body = "{"link_with":"SECONDARY_ACCOUNT_ID_TOKEN"}"

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

<h2 id="auth0js-library">
  Bibliothèque Auth0.js
</h2>

Vous pouvez utiliser la bibliothèque Auth0.js pour effectuer la liaison de comptes côté client. Consultez [Référence Auth0.js > Gestion des utilisateurs](/docs/fr-ca/libraries/auth0js#user-management) pour en savoir plus.


## Related topics

- [Unlink User Accounts](/docs/manage-users/user-accounts/user-account-linking/unlink-user-accounts.md)
- [User-Initiated Account Linking: Client-Side Implementation](/docs/manage-users/user-accounts/user-account-linking/user-initiated-account-linking-client-side-implementation.md)
- [User Account Linking: Server-Side Implementation](/docs/manage-users/user-accounts/user-account-linking/suggested-account-linking-server-side-implementation.md)
