Gérer les erreurs et les exceptions dans MSAL.NET

Cet article fournit une vue d’ensemble des différents types d’erreurs et de recommandations pour la gestion des erreurs de connexion courantes.

Concepts de base de la gestion des erreurs MSAL

Les exceptions dans Microsoft Authentication Library (MSAL) sont destinées aux développeurs d’applications pour résoudre les problèmes, et non pour l’affichage aux utilisateurs finaux. Les messages d’exception ne sont pas localisés.

Lors du traitement des exceptions et des erreurs, vous pouvez utiliser le type d’exception lui-même et le code d’erreur pour distinguer les exceptions. Pour obtenir la liste des codes d’erreur, consultez Microsoft Entra codes d’erreur d’authentification et d’autorisation.

Pendant l’expérience de connexion, vous pouvez rencontrer des erreurs concernant les consentements, l’accès conditionnel (MFA, Gestion des appareils, restrictions basées sur l’emplacement), l’émission et l’échange de jetons et les propriétés utilisateur.

La section suivante fournit plus d’informations sur la gestion des erreurs pour votre application.

Gestion des erreurs dans MSAL.NET

Types d’exceptions

MsalClientException est levée lorsque la bibliothèque elle-même détecte un état d’erreur, tel qu’une configuration incorrecte.

MsalServiceException est levée lorsque le fournisseur d’identité (Microsoft Entra ID) retourne une erreur. Il s’agit d’une traduction de l’erreur du serveur.

MsalUIRequiredException est de type MsalServiceException et indique que l’interaction utilisateur est requise. Par exemple, lorsque l’authentification multifacteur (MFA) est requise ou lorsque l’utilisateur modifie son mot de passe et qu’un jeton ne peut pas être acquis en mode silencieux.

Traitement des exceptions

Lors du traitement .NET exceptions, vous pouvez utiliser le type d’exception lui-même et le ErrorCode membre pour faire la distinction entre les exceptions. ErrorCode les valeurs sont des constantes de type MsalError.

Vous pouvez également examiner les champs de MsalClientException, MsalServiceException et MsalUIRequiredException.

Si MsalServiceException est levée, consultez les codes d’erreur d’authentification et d’autorisation pour vérifier si le code y figure.

Si MsalUIRequiredException est levée, il s’agit d’une indication qu’un flux interactif doit se produire pour que l’utilisateur résolve le problème. Dans les applications clientes publiques telles que les applications de bureau et mobiles, ce problème est résolu en appelant AcquireTokenInteractive, ce qui ouvre une fenêtre de navigateur. Dans les applications clientes confidentielles, les applications web doivent rediriger l’utilisateur vers la page d’autorisation, et les API web doivent retourner un code d’état HTTP et un en-tête indiquant l’échec de l’authentification (401 Non autorisé et un en-tête WWW-Authenticate).

Exceptions courantes .NET

Voici les exceptions courantes qui peuvent être levées et certaines atténuations possibles :

Exception Code d'erreur Mitigation
MsalUiRequiredException AADSTS65001 : l’utilisateur ou l’administrateur n’a pas accepté d’utiliser l’application avec l’ID « {appId} » nommé « {appName} ». Envoyez une demande d’autorisation interactive pour cet utilisateur et cette ressource. Obtenez d’abord le consentement de l’utilisateur. Si vous n'utilisez pas .NET Core (qui n'a pas d'interface utilisateur web), appelez (une seule fois). AcquireTokenInteractive Si vous utilisez .NET Core ou que vous ne souhaitez pas faire de AcquireTokenInteractive, l'utilisateur peut accéder à l'URL suivante pour accorder son consentement : https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read. pour appeler AcquireTokenInteractive: app.AcquireTokenInteractive(scopes).WithAccount(account).WithClaims(ex.Claims).ExecuteAsync();
MsalUiRequiredException AADSTS50079 : l’utilisateur doit utiliser l’authentification multifacteur (MFA). Il n’y a pas d’atténuation. Si l’authentification multifacteur est configurée pour votre locataire et que Microsoft Entra ID décide de l’appliquer, revenez à un flux interactif tel que AcquireTokenInteractive.
MsalServiceException AADSTS90010 : le type d’octroi n’est pas pris en charge sur les points de terminaison /common ou /consumers . Utilisez le point de terminaison /organizations ou spécifique au locataire. Vous avez utilisé /common. Comme expliqué dans le message de Microsoft Entra ID, l’autorité doit avoir un tenant ou, à défaut, /organizations.
MsalServiceException AADSTS70002 : le corps de la requête doit contenir le paramètre suivant : client_secret or client_assertion. Cette exception peut être levée si votre application n'a pas été inscrite en tant qu'application cliente publique dans Microsoft Entra ID. Dans le centre d’administration Microsoft Entra, modifiez le manifeste de votre application et définissez allowPublicClient sur true.
MsalClientException unknown_user Message: Impossible d’identifier l’utilisateur connecté La bibliothèque n'a pas pu interroger l’utilisateur Windows actuellement connecté, ou cet utilisateur n’est pas joint à Active Directory ou à Microsoft Entra (les utilisateurs joints à un lieu de travail ne sont pas pris en charge). Atténuation : implémentez votre propre logique pour récupérer le nom d’utilisateur (par exemple john@contoso.com) et utilisez le AcquireTokenByIntegratedWindowsAuth formulaire qui prend le nom d’utilisateur.
MsalClientException L’authentification Windows intégrée n’est pas prise en charge pour les utilisateurs gérés. Cette méthode s’appuie sur un protocole exposé par Active Directory (AD). Si un utilisateur a été créé dans Microsoft Entra ID sans prise en charge par AD (« géré »), cette méthode échoue. Les utilisateurs créés dans AD et soutenus par Microsoft Entra ID « utilisateurs fédérés » peuvent tirer parti de cette méthode d’authentification non interactive. Atténuation : utilisez l’authentification interactive.

MsalUiRequiredException

Un des codes d’état courants retournés par MSAL.NET lors de l’appel AcquireTokenSilent() est MsalError.InvalidGrantError. Ce code d’état signifie que l’application doit appeler à nouveau la bibliothèque d’authentification, mais en mode interactif (AcquireTokenInteractive ou AcquireTokenByDeviceCodeFlow pour les applications clientes publiques, rencontrez un défi dans les applications web). Cela est dû au fait que d’autres interactions utilisateur sont requises avant que le jeton d’authentification puisse être émis.

La plupart du temps en cas AcquireTokenSilent d’échec, c’est parce que le cache de jetons n’a pas de jetons correspondant à votre demande. Les jetons d’accès expirent en 1 heure et AcquireTokenSilent essaient d’extraire un nouveau jeton en fonction d’un jeton d’actualisation (en termes OAuth2, il s’agit du flux « Jeton d’actualisation »). Ce flux peut également échouer pour différentes raisons, par exemple si un administrateur client configure des stratégies de connexion plus strictes.

L’interaction vise à ce que l’utilisateur effectue une action. Certaines de ces conditions sont faciles à résoudre pour les utilisateurs (par exemple, accepter les conditions d’utilisation en un seul clic) et certaines ne peuvent pas être résolues avec la configuration actuelle (par exemple, l’ordinateur en question doit se connecter à un réseau d’entreprise spécifique). Certains aident l’utilisateur à configurer l’authentification multifacteur ou à installer Microsoft Authenticator sur son appareil.

MsalUiRequiredException énumération de classes

MSAL expose un Classification champ, que vous pouvez lire pour offrir une meilleure expérience utilisateur. Par exemple, pour indiquer à l’utilisateur que son mot de passe a expiré ou qu’il doit fournir le consentement pour utiliser certaines ressources. Les valeurs prises en charge font partie de l’énumération UiRequiredExceptionClassification :

Classification Sens Gestion recommandée
BasicAction La condition peut être résolue par l’interaction de l’utilisateur pendant le flux d’authentification interactif. Appelez AcquireTokenInteractively().
Action supplémentaire La condition peut être résolue par une interaction corrective supplémentaire avec le système, en dehors du flux d’authentification interactif. Appelez AcquireTokenInteractively() pour afficher un message qui explique l’action corrective. L’application appelante peut choisir de masquer les flux qui nécessitent une action supplémentaire si l’utilisateur est peu susceptible de mener l’action corrective à bien.
MessageOnly La condition ne peut pas être résolue pour l’instant. Le lancement d’un flux d’authentification interactif affiche un message expliquant la condition. Appelez AcquireTokenInteractively() pour afficher un message qui explique la condition. AcquireTokenInteractively() renvoie l’erreur UserCanceled une fois que l’utilisateur a lu le message et ferme la fenêtre. L’application appelante peut choisir de masquer les flux qui entraînent message_only si l’utilisateur ne peut pas tirer parti du message.
Consentement requis Le consentement de l’utilisateur est manquant ou a été révoqué. Appelez AcquireTokenInteractively() pour que l’utilisateur donne son consentement.
Le mot de passe de l’utilisateur a expiré Le mot de passe de l’utilisateur a expiré. Appelez AcquireTokenInteractively() afin que l’utilisateur puisse réinitialiser son mot de passe.
PromptNeverFailed L’authentification interactive a été invoquée avec le paramètre prompt=never, ce qui force MSAL à s’appuyer sur les cookies du navigateur sans afficher le navigateur. Cela a échoué. Appelez AcquireTokenInteractively() sans utiliser Prompt.None
AcquireTokenSilentFailed Le Kit de développement logiciel (SDK) MSAL n’a pas suffisamment d’informations pour récupérer un jeton à partir du cache. Cela peut être dû au fait qu’aucun jeton n’est présent dans le cache ou qu’un compte n’a pas été trouvé. Le message d’erreur contient plus de détails. Appelez AcquireTokenInteractively().
None Aucun détail supplémentaire n’est fourni. La condition peut être résolue par l’interaction de l’utilisateur pendant le flux d’authentification interactif. Appelez AcquireTokenInteractively().

exemple de code .NET

AuthenticationResult res;
try
{
 res = await application.AcquireTokenSilent(scopes, account)
        .ExecuteAsync();
}
catch (MsalUiRequiredException ex) when (ex.ErrorCode == MsalError.InvalidGrantError)
{
 switch (ex.Classification)
 {
  case UiRequiredExceptionClassification.None:
   break;
  case UiRequiredExceptionClassification.MessageOnly:
  // You might want to call AcquireTokenInteractive(). Azure AD will show a message
  // that explains the condition. AcquireTokenInteractively() will return UserCanceled error
  // after the user reads the message and closes the window. The calling application may choose
  // to hide features or data that result in message_only if the user is unlikely to benefit 
  // from the message
  try
  {
      res = await application.AcquireTokenInteractive(scopes).ExecuteAsync();
  }
  catch (MsalClientException ex2) when (ex2.ErrorCode == MsalError.AuthenticationCanceledError)
  {
   // Do nothing. The user has seen the message
  }
  break;

  case UiRequiredExceptionClassification.BasicAction:
  // Call AcquireTokenInteractive() so that the user can, for instance accept terms
  // and conditions

  case UiRequiredExceptionClassification.AdditionalAction:
  // You might want to call AcquireTokenInteractive() to show a message that explains the remedial action. 
  // The calling application may choose to hide flows that require additional_action if the user 
  // is unlikely to complete the remedial action (even if this means a degraded experience)

  case UiRequiredExceptionClassification.ConsentRequired:
  // Call AcquireTokenInteractive() for user to give consent.
  
  case UiRequiredExceptionClassification.UserPasswordExpired:
  // Call AcquireTokenInteractive() so that user can reset their password
  
  case UiRequiredExceptionClassification.PromptNeverFailed:
  // You used WithPrompt(Prompt.Never) and this failed
  
  case UiRequiredExceptionClassification.AcquireTokenSilentFailed:
  default:
  // May be resolved by user interaction during the interactive authentication flow.
  res = await application.AcquireTokenInteractive(scopes)
                         .ExecuteAsync(); break;
 }
}

Défis liés à l’accès conditionnel et aux revendications

Lorsque vous obtenez des jetons en mode silencieux, votre application peut recevoir des erreurs lorsqu’une demande de revendications d’accès conditionnel , telle que la stratégie MFA, est requise par une API que vous essayez d’accéder.

Le modèle de gestion de cette erreur consiste à acquérir de manière interactive un jeton à l’aide de MSAL. Cela invite l’utilisateur et lui donne la possibilité de se conformer à la stratégie d’accès conditionnel requise.

Dans certains cas, lors de l’appel d’une API nécessitant l’accès conditionnel, vous pouvez recevoir une demande de revendications dans le message d’erreur renvoyé par l’API. Par exemple, si la stratégie d’accès conditionnel doit avoir un appareil managé (Intune) l’erreur sera quelque chose comme AADSTS53000 : votre appareil doit être géré pour accéder à cette ressource ou quelque chose de similaire. Dans ce cas, vous pouvez transmettre les claims dans l’appel à acquireToken afin que l’utilisateur soit invité à se conformer à la stratégie appropriée.

Lors de l’appel d’une API nécessitant un accès conditionnel à partir de MSAL.NET, votre application doit gérer les exceptions de défi de revendication. Cela s’affiche en tant que MsalServiceException où la propriété Claims ne sera pas vide.

Pour gérer la contestation de réclamation, utilisez WithClaims(String).

Nouvelle tentative après des erreurs et des exceptions

Vous devez mettre en œuvre vos propres stratégies de réessai lors de l’appel à MSAL. MSAL effectue des appels HTTP au service Microsoft Entra, et parfois des échecs peuvent se produire. Par exemple, le réseau peut descendre ou le serveur est surchargé.

HTTP 429

Lorsque le serveur de jetons de service (STS) est surchargé avec trop de requêtes, il retourne l’erreur HTTP 429 avec un indicateur sur la durée jusqu’à ce que vous puissiez réessayer dans le Retry-After champ de réponse.

Codes d’erreur HTTP 500-600

MSAL.NET implémente un mécanisme simple de nouvelle tentative pour les erreurs avec les codes d’erreur HTTP 500-600.

MsalServiceException s’affiche System.Net.Http.Headers.HttpResponseHeaders en tant que propriété namedHeaders. Vous pouvez utiliser des informations supplémentaires à partir du code d’erreur pour améliorer la fiabilité de vos applications. Dans le cas décrit, vous pouvez utiliser la propriété RetryAfter (de type RetryConditionHeaderValue) et calculer quand effectuer une nouvelle tentative.

Voici un exemple d’application démon utilisant le flux d’informations d’identification du client. Vous pouvez l’adapter à l’une des méthodes permettant d’acquérir un jeton.


bool retry = false;
do
{
    TimeSpan? delay;
    try
    {
         result = await publicClientApplication.AcquireTokenForClient(scopes, account).ExecuteAsync();
    }
    catch (MsalServiceException serviceException)
    {
         if (serviceException.ErrorCode == "temporarily_unavailable")
         {
             RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter;
             if (retryAfter.Delta.HasValue)
             {
                 delay = retryAfter.Delta;
             }
             else if (retryAfter.Date.HasValue)
             {
                 delay = (retryAfter.Date.Value – DateTimeOffset.Now).TotalMilliseconds;
             }
         }
    }
    // . . .
    if (delay.HasValue)
    {
        Thread.Sleep((int)delay.Value.TotalMilliseconds); // sleep or other
        retry = true;
    }
} while (retry);

Étapes suivantes

Envisagez d’activer la journalisation dans MSAL.NET pour vous aider à diagnostiquer et déboguer les problèmes.