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

> Découvrez comment authentifier des utilisateurs à l’aide du Resource Owner Password Flow avec MFA.

# Authentifier des utilisateurs à l’aide du Resource Owner Password Flow avec MFA

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>;
};

Vous pouvez utiliser l’[Auth0 MFA API](https://auth0.com/docs/api/authentication#multi-factor-authentication) pour mener à bien le flux d’authentification à l’aide du [Resource Owner Password Flow](/docs/fr-ca/get-started/authentication-and-authorization-flow/resource-owner-password-flow) (parfois appelé <Tooltip tip="Resource Owner : entité (comme un utilisateur ou une application) capable d’accorder l’accès à une ressource protégée." cta="Voir le glossaire" href="/docs/fr-ca/glossary?term=Resource+Owner">Resource Owner</Tooltip> Password Grant ou ROPG) lorsque la <Tooltip tip="Resource Owner : entité (comme un utilisateur ou une application) capable d’accorder l’accès à une ressource protégée." cta="Voir le glossaire" href="/docs/fr-ca/glossary?term=MFA">MFA</Tooltip> est activée.

<div id="prerequisites">
  ## Prérequis
</div>

Pour pouvoir utiliser les API MFA, vous devez activer le type d’octroi MFA pour votre application. Accédez à [Auth0 Dashboard > Applications > Advanced Settings > Grant Types](https://manage.auth0.com/#/applications) et sélectionnez **MFA**.

<div id="authenticate-user">
  ## Authentifier un utilisateur
</div>

Lorsque vous utilisez le Resource Owner Password Flow pour authentifier un utilisateur, vous envoyez une requête au point de terminaison `/oauth/token` avec le nom d’utilisateur et le mot de passe de l’utilisateur.

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/oauth/token' \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data grant_type=password \
    --data username=user@example.com \
    --data password=pwd \
    --data 'client_id={yourClientId}' \
    --data 'client_secret={yourClientSecret}' \
    --data audience=https://someapi.com/api \
    --data 'scope=openid profile read:sample'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/oauth/token");
  var request = new RestRequest(Method.POST);
  request.AddHeader("content-type", "application/x-www-form-urlencoded");
  request.AddParameter("application/x-www-form-urlencoded", "grant_type=password&username=user%40example.com&password=pwd&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&audience=https%3A%2F%2Fsomeapi.com%2Fapi&scope=openid%20profile%20read%3Asample", 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}/oauth/token"

  	payload := strings.NewReader("grant_type=password&username=user%40example.com&password=pwd&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&audience=https%3A%2F%2Fsomeapi.com%2Fapi&scope=openid%20profile%20read%3Asample")

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

  	req.Header.Add("content-type", "application/x-www-form-urlencoded")

  	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 response = Unirest.post("https://{yourDomain}/oauth/token")
    .header("content-type", "application/x-www-form-urlencoded")
    .body("grant_type=password&username=user%40example.com&password=pwd&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&audience=https%3A%2F%2Fsomeapi.com%2Fapi&scope=openid%20profile%20read%3Asample")
    .asString();
  ```

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

  var options = {
    method: 'POST',
    url: 'https://{yourDomain}/oauth/token',
    headers: {'content-type': 'application/x-www-form-urlencoded'},
    data: new URLSearchParams({
      grant_type: 'password',
      username: 'user@example.com',
      password: 'pwd',
      client_id: '{yourClientId}',
      client_secret: '{yourClientSecret}',
      audience: 'https://someapi.com/api',
      scope: 'openid profile read:sample'
    })
  };

  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}/oauth/token",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => "grant_type=password&username=user%40example.com&password=pwd&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&audience=https%3A%2F%2Fsomeapi.com%2Fapi&scope=openid%20profile%20read%3Asample",
    CURLOPT_HTTPHEADER => [
      "content-type: application/x-www-form-urlencoded"
    ],
  ]);

  $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 = "grant_type=password&username=user%40example.com&password=pwd&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&audience=https%3A%2F%2Fsomeapi.com%2Fapi&scope=openid%20profile%20read%3Asample"

  headers = { 'content-type': "application/x-www-form-urlencoded" }

  conn.request("POST", "/{yourDomain}/oauth/token", 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}/oauth/token")

  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["content-type"] = 'application/x-www-form-urlencoded'
  request.body = "grant_type=password&username=user%40example.com&password=pwd&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&audience=https%3A%2F%2Fsomeapi.com%2Fapi&scope=openid%20profile%20read%3Asample"

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

Lorsque l’authentification multifacteur (MFA) est activée, la réponse contient une erreur `mfa_required` et un `mfa_token`.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  La durée d’expiration par défaut des jetons d’accès ayant l’audience `https://{yourDomain}/mfa/*` est de 10 minutes. Cette valeur n’est pas configurable.
</Callout>

```json lines theme={null}
{
    "error": "mfa_required",
    "error_description": "Multifactor authentication required",
    "mfa_token": "Fe26...Ha"
}
```

<div id="retrieve-enrolled-authenticators">
  ## Récupérer les authentificateurs inscrits
</div>

Après avoir obtenu l’erreur ci-dessus, vous devez déterminer si l’utilisateur a inscrit un facteur MFA ou non. Effectuez une requête au [point de terminaison MFA Authenticators](/docs/fr-ca/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api) en utilisant le jeton MFA obtenu dans la section précédente.

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://{yourDomain}/mfa/authenticators' \
    --header 'authorization: Bearer MFA_TOKEN' \
    --header 'content-type: application/json'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/mfa/authenticators");
  var request = new RestRequest(Method.GET);
  request.AddHeader("authorization", "Bearer MFA_TOKEN");
  request.AddHeader("content-type", "application/json");
  IRestResponse response = client.Execute(request);
  ```

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

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

  func main() {

  	url := "https://{yourDomain}/mfa/authenticators"

  	req, _ := http.NewRequest("GET", url, nil)

  	req.Header.Add("authorization", "Bearer MFA_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.get("https://{yourDomain}/mfa/authenticators")
    .header("authorization", "Bearer MFA_TOKEN")
    .header("content-type", "application/json")
    .asString();
  ```

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

  var options = {
    method: 'GET',
    url: 'https://{yourDomain}/mfa/authenticators',
    headers: {authorization: 'Bearer MFA_TOKEN', 'content-type': 'application/json'}
  };

  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}/mfa/authenticators",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MFA_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("")

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

  conn.request("GET", "/{yourDomain}/mfa/authenticators", headers=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}/mfa/authenticators")

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

  request = Net::HTTP::Get.new(url)
  request["authorization"] = 'Bearer MFA_TOKEN'
  request["content-type"] = 'application/json'

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

Vous recevrez un tableau contenant les authentificateurs disponibles. Le tableau sera vide si l’utilisateur n’a inscrit aucun facteur.

```json lines theme={null}
[
    {
        "id": "recovery-code|dev_O4KYL4FtcLAVRsCl",
        "authenticator_type": "recovery-code",
        "active": true
    },
    {
        "id": "email|dev_NU1Ofuw3Cw0XCt5x",
        "authenticator_type": "oob",
        "active": true,
        "oob_channel": "email",
        "name": "email@address.com"
    }
]
```

<div id="enroll-mfa-factor">
  ## Inscrire un facteur MFA
</div>

Si l’utilisateur n’est pas inscrit à la MFA, utilisez le jeton MFA obtenu précédemment pour inscrire un facteur à l’aide du endpoint MFA Associate. Consultez les liens suivants pour mettre en œuvre ce flux selon le facteur d’authentification :

* [SMS ou appel vocal](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators)
* [Mot de passe à usage unique (OTP)](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-otp-authenticators)
* [Push](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-push-authenticators)
* [Courriel](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-email-authenticators)

<div id="challenge-user-with-mfa">
  ## Défi de l’utilisateur avec MFA
</div>

Si l’utilisateur est déjà inscrit à la MFA, vous devez lui demander de confirmer son identité à l’aide de l’un des facteurs existants. Utilisez le `authenticator_id` renvoyé par le point de terminaison MFA Authenticators lorsque vous appelez le point de terminaison MFA Défi.

Une fois le défi terminé, appelez de nouveau le point de terminaison `/oauth/token` pour finaliser le flux d’authentification et obtenir les jetons d’authentification.

Consultez les liens ci-dessous pour mettre en œuvre ce flux selon le facteur d’authentification :

* [SMS ou appel vocal](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators)
* [Mot de passe à usage unique (OTP)](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-otp-authenticators)
* [Push](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-push-authenticators)
* [courriel](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-email-authenticators)

<div id="mfa-otp-code-limitations-and-restrictions">
  ### Limites et restrictions des codes OTP MFA
</div>

**Délai d’expiration** : Le délai d’expiration des codes OTP MFA est de 5 minutes. Cette valeur n’est pas configurable.

**Validation du code** : Après qu’un utilisateur a validé un code OTP MFA, ce code ne peut plus être réutilisé.

**Limitation du nombre de validations du code** : Les tentatives de validation infructueuses sont soumises à une limitation du nombre de requêtes au moyen d’un algorithme de seau. Le seau contient au départ 10 tentatives et se recharge à raison d’une tentative toutes les 6 minutes.

<div id="customize-mfa">
  ## Personnaliser la MFA
</div>

<Warning>
  La MFA personnalisable avec les flux Resource Owner Password Grant, Embedded ou Refresh Token est en accès anticipé. En utilisant cette fonctionnalité, vous acceptez les conditions d’essai gratuit applicables de l’[Master Subscription Agreement](https://www.okta.com/legal/) d’Okta. Pour en savoir plus sur les étapes de lancement d’Auth0, consultez [Product Release Stages](/docs/fr-ca/troubleshoot/product-lifecycle/product-release-stages). Pour participer à l’accès anticipé, communiquez avec [Auth0 Support](https://support.auth0.com/).
</Warning>

Personnalisez vos flux MFA avec la MFA API. Avec la MFA API, vous pouvez permettre à vos utilisateurs d’inscrire des facteurs et de répondre à des défis à l’aide d’un ensemble précis de facteurs pris en charge par votre application.

Lorsque la MFA est activée avec le Resource Owner Password Flow pour authentifier l’utilisateur, envoyez une requête au point de terminaison `/oauth/token endpoint` pour demander un jeton d’accès. Le serveur d’autorisation renvoie une erreur `mfa_required` qui fournit :

* Le `mfa_token` dont vous avez besoin pour appeler la MFA API pour l’inscription et les défis.
* Le paramètre `mfa_requirements`, qui indique le type de facteur pris en charge par votre application pour les défis.

```json theme={null}
{
  "error": "mfa_required",
  "error_description": "Multifactor authentication required",
  "mfa_token": "Fe26...Ha",
  "mfa_requirements": {
    "challenge": [
      { "type": "otp" },
      { "type": "push-notification" },
      { "type": "phone" },
      { "type": "recovery-code" }
    ]
  }
}
```

Utilisez le `mfa_token` pour effectuer une requête à l’[`mfa/authenticator endpoint`](/docs/fr-ca/api/authentication/muti-factor-authentication/list-authenticators) afin de lister tous les facteurs que l’utilisateur a enregistrés et de repérer celui du même type que celui pris en charge par votre application.  Vous devez aussi obtenir l’`authenticator_type` correspondant pour émettre des défis :

```json theme={null}
[
  {
    "type": "recovery-code",
    "id": "recovery-code|dev_qpOkGUOxBpw6R16t",
    "authenticator_type": "recovery-code",
    "active": true
  },
  {
    "type": "otp",
    "id": "totp|dev_6NWz8awwC8brh2dN",
    "authenticator_type": "otp",
    "active": true
  }
]
```

Imposez le défi MFA en appelant le point de terminaison [`request/mfa/challenge`](/docs/fr-ca/api/authentication/muti-factor-authentication/request-mfa-challenge).

Personnalisez davantage votre flux MFA avec Auth0 Actions. Pour en savoir plus, consultez [Actions Triggers: post-challenge - API Object](/docs/fr-ca/customize/actions/explore-triggers/password-reset-triggers/post-challenge-trigger/post-challenge-api-object).

<div id="learn-more">
  ## En savoir plus
</div>

* [Inscrire et lancer des défis avec les authentificateurs SMS et appel vocal](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators)
* [Inscrire et lancer des défis avec les authentificateurs OTP](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-otp-authenticators)
* [Inscrire et lancer des défis avec les authentificateurs push](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-push-authenticators)
* [Inscrire et lancer des défis avec les authentificateurs courriel](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-email-authenticators)
* [Gérer les facteurs d’authentification avec l’Authentication API](/docs/fr-ca/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api)
* [Facteurs d’authentification multifacteur](/docs/fr-ca/secure/multi-factor-authentication/multi-factor-authentication-factors)
