> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentifier par un flux de mot de passe du propriétaire de ressource avec MFA

> Découvrez comment authentifier les utilisateurs en utilisant le flux de mot de passe du propriétaire de ressource avec l’authentification multifacteur (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) + "*****MASKED*****";
          }
          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’API Auth0 pour l’authentification multifacteur (MFA)](/docs/fr-ca/api/authentication#multi-factor-authentication) pour compléter le flux d’authentification à l’aide du [Flux de mot de passe du propriétaire de ressource](/docs/fr-ca/get-started/authentication-and-authorization-flow/resource-owner-password-flow) (parfois appelé Autorisation de mot de passe du propriétaire des ressources ou ROPG lorsque <Tooltip href="/docs/fr-ca/glossary?term=multifactor-authentication" tip="Authentification multifacteur (MFA)
Processus d’authentification de l’utilisateur qui utilise un facteur en plus du nom d’utilisateur et du mot de passe, tel qu’un code par SMS." cta="Voir le glossaire">MFA</Tooltip> est activée.

## Prérequis

Avant de pouvoir utiliser les API MFA, vous devrez activer le type d’autorisation MFA pour votre application. Accédez à [Auth0 Dashboard > Applications > Paramètres avancés > Types d’autorisation](https://manage.auth0.com/#/applications) et sélectionnez **MFA**.

## Authentifier l’utilisateur

Lorsque vous utilisez le Flux de mot de passe du propriétaire de ressource pour l’authentification, vous appelez le 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);
  });
  ```

  ```objc Obj-C theme={null}
  #import <Foundation/Foundation.h>

  NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };

  NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"grant_type=password" dataUsingEncoding:NSUTF8StringEncoding]];
  [postData appendData:[@"&username=user@example.com" dataUsingEncoding:NSUTF8StringEncoding]];
  [postData appendData:[@"&password=pwd" dataUsingEncoding:NSUTF8StringEncoding]];
  [postData appendData:[@"&client_id={yourClientId}" dataUsingEncoding:NSUTF8StringEncoding]];
  [postData appendData:[@"&client_secret={yourClientSecret}" dataUsingEncoding:NSUTF8StringEncoding]];
  [postData appendData:[@"&audience=https://someapi.com/api" dataUsingEncoding:NSUTF8StringEncoding]];
  [postData appendData:[@"&scope=openid profile read:sample" dataUsingEncoding:NSUTF8StringEncoding]];

  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/token"]
                                                         cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                     timeoutInterval:10.0];
  [request setHTTPMethod:@"POST"];
  [request setAllHTTPHeaderFields:headers];
  [request setHTTPBody:postData];

  NSURLSession *session = [NSURLSession sharedSession];
  NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                              completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                  if (error) {
                                                      NSLog(@"%@", error);
                                                  } else {
                                                      NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                      NSLog(@"%@", httpResponse);
                                                  }
                                              }];
  [dataTask resume];
  ```

  ```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_NONE

  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
  ```

  ```swift Swift theme={null}
  import Foundation

  let headers = ["content-type": "application/x-www-form-urlencoded"]

  let postData = NSMutableData(data: "grant_type=password".data(using: String.Encoding.utf8)!)
  postData.append("&username=user@example.com".data(using: String.Encoding.utf8)!)
  postData.append("&password=pwd".data(using: String.Encoding.utf8)!)
  postData.append("&client_id={yourClientId}".data(using: String.Encoding.utf8)!)
  postData.append("&client_secret={yourClientSecret}".data(using: String.Encoding.utf8)!)
  postData.append("&audience=https://someapi.com/api".data(using: String.Encoding.utf8)!)
  postData.append("&scope=openid profile read:sample".data(using: String.Encoding.utf8)!)

  let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/token")! as URL,
                                          cachePolicy: .useProtocolCachePolicy,
                                      timeoutInterval: 10.0)
  request.httpMethod = "POST"
  request.allHTTPHeaderFields = headers
  request.httpBody = postData as Data

  let session = URLSession.shared
  let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
    if (error != nil) {
      print(error)
    } else {
      let httpResponse = response as? HTTPURLResponse
      print(httpResponse)
    }
  })

  dataTask.resume()
  ```
</AuthCodeGroup>

Lorsque MFA est activé, la réponse comprend une erreur `mfa_required` et un jeton `mfa_token`.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Le délai d’expiration par défaut des jetons d’accès avec l’audience `https://{yourDomain}/mfa/*` est de 10 minutes. Cette valeur ne peut pas être configurée.
</Callout>

Après avoir reçu l’erreur ci-dessus, vous devez vérifier si l’utilisateur a un facteur MFA enregistré ou non. Appelez le point de terminaison [MFA Authenticators](/docs/fr-ca/secure/multi-factor-authentication/manage-mfa-auth0-apis/manage-authenticator-factors-mfa-api) (Authentificateurs MFA), en utilisant le jeton MFA obtenu dans la section précédente.

## Récupérer les facteurs d’authentification enregistrés

Après avoir reçu l'erreur ci-dessus, vous devez vérifier si l'utilisateur a un facteur MFA enregistré ou non. Appelez le point de terminaison [Authentificateurs MFA](/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.

Vous recevrez un tableau avec les facteurs d’authentification disponibles. Le tableau sera vide si l’utilisateur n’a pas enregistré de facteur.

Vous recevrez un tableau avec les facteurs d'authentification disponibles. Le tableau sera vide si l'utilisateur n'a pas enregistré de facteur.

Si l’utilisateur n’est pas enregistré dans MFA, utilisez un jeton MFA obtenu précédemment et enregistrez-le en utilisant le point de terminaison MFA Associate. Consultez les liens suivants pour mettre en œuvre ce flux basé sur le facteur d’authentification :

## Enregistrer un facteur MFA

Si l’utilisateur est déjà enregistré pour l’authentification MFA, vous devez le défier avec l’un des facteurs existants. Utiliser le retour `authenticator_id` du point de terminaison des authentificateurs MFA lors de l’appel au point de terminaison du défi MFA.

* [SMS ou voix](/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)
* [Courriel](/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)

## Défier l’utilisateur avec la MFA

Si l'utilisateur est déjà enregistré pour l'authentification MFA, vous devez le défier avec l'un des facteurs existants. Utiliser le retour `authenticator_id` du point de terminaison des authentificateurs MFA lors de l’appel au point de terminaison du défi MFA.

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 en fonction du facteur d’authentification :

* [SMS ou voix](/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)
* [Courriel](/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)

### Limitations et restrictions des codes OTP pour l’authentification MFA

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

**Validation du code** : Une fois qu’un utilisateur a utilisé un code OTP pour l’authentification MFA, ce code ne peut plus être utilisé.

**Limite anti-attaques de validation des codes** : Les tentatives de validation infructueuses de l’utilisateur ont une limite anti-attaques limitée par un algorithme de tri par casiers. L’algorithme autorise 10 tentatives, puis se rafraîchit pour autoriser ensuite une nouvelle tentative toutes les 6 minutes.

## En savoir plus

* [Facteurs d’authentification SMS et vocaux pour l’inscription et les défis de connexion](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-challenge-sms-voice-authenticators)
* [Inscription et défi des authentificateurs OTP](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-otp-authenticators)
* [Inscrire et lancer un défi-réponse pour les authentifiants Push](/docs/fr-ca/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa/enroll-and-challenge-push-authenticators)
* [Inscription et authentifiants par défi-réponse avec 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 (MFA)](/docs/fr-ca/secure/multi-factor-authentication/multi-factor-authentication-factors)
