« On a créé un écran de connexion pour chaque application métier interne et on gère les mots de passe dans notre propre base de données. À chaque départ, c’est pénible de devoir désactiver le compte application par application. » « Microsoft 365 est déployé dans toute l’entreprise, ne pourrait-on pas simplement laisser les gens se connecter avec ce même compte ? » Voici des thématiques qui reviennent de façon de plus en plus régulière dans nos consultations de refonte d’applications de bureau, depuis quelques années. Il arrive aussi que la demande prenne une autre forme : le service informatique demande à l’équipe métier « d’arrêter de gérer ses propres mots de passe », dans le contexte d’un incident de fuite de mots de passe ou d’une démarche de zero trust.
Pour aller droit au but : dans une organisation qui utilise Microsoft 365, faire basculer la connexion des applications internes WinForms / WPF vers Entra ID (anciennement Azure AD) est un investissement judicieux. L’application cesse totalement de conserver des mots de passe, et les défenses et l’audit côté tenant — authentification multifacteur, accès conditionnel, journaux de connexion — s’appliquent alors directement aux applications internes. La mise en œuvre elle-même tient dans une bibliothèque appelée MSAL.NET et quelques dizaines de lignes de code.
Cela dit, les applications de bureau ont leurs pièges propres. La façon de faire à l’ancienne — « recueillir le nom d’utilisateur et le mot de passe dans une zone de texte et authentifier en coulisses » (ROPC) — est officiellement en voie de dépréciation et ne doit pas être adoptée pour un nouveau développement. Sans persistance du cache de jetons, l’écran de connexion réapparaît à chaque démarrage, et sous Windows, le fait d’utiliser ou non un broker (WAM) change radicalement l’expérience et la sécurité. Cet article couvre l’ensemble du sujet : une mise au point minimale des concepts, l’inscription de l’application, l’implémentation avec MSAL.NET, WAM, le cache, le jugement d’adoption et les pièges opérationnels.
1. L’essentiel d’abord
- Abandonner la gestion maison des identifiants et mots de passe au profit d’Entra ID fait que le stockage des mots de passe, la prise en charge des réinitialisations, la désactivation des comptes des personnes qui partent et l’audit des connexions deviennent entièrement l’affaire du tenant. La réduction radicale du périmètre de responsabilité de l’application est le principal bénéfice.
- Une application de bureau est un client public. Comme l’exécutable peut être analysé sur le poste où il est distribué, il ne peut pas (et ne doit pas) détenir de secret client. L’inscription de l’application doit elle aussi être configurée comme un client public. 1
- Le ROPC (Resource Owner Password Credentials), où l’application recueille elle-même directement le nom d’utilisateur et le mot de passe, est officiellement documenté comme « déprécié », avec un guide de migration publié en parallèle. Il n’est pas compatible avec la MFA et l’accès conditionnel, et devient de fait inutilisable. Considérez son adoption comme interdite pour tout nouveau développement. 23
- L’implémentation repose sur MSAL.NET (Microsoft.Identity.Client), avec un seul schéma d’appel de base à retenir : appeler d’abord
AcquireTokenSilent, puis ne basculer versAcquireTokenInteractivequ’en cas deMsalUiRequiredException. 4 - Sous Windows, l’authentification via le broker WAM (Web Account Manager) est recommandée. Le SSO avec le compte déjà connecté à Windows, la prise en charge de l’accès conditionnel, de Windows Hello et des clés FIDO, ainsi que la liaison des jetons d’actualisation à l’appareil, s’obtiennent tous avec une seule ligne,
WithBroker. 5 - Oubliez de persister le cache de jetons, et l’écran de connexion réapparaît à chaque redémarrage de l’application. Intégrez dès le départ le cache chiffré de
Microsoft.Identity.Client.Extensions.Msal. 6 - L’authentification Entra est un mécanisme qui suppose un réseau. Elle ne fonctionne pas pour les applications de terrain qui doivent tourner entièrement hors ligne ; utilisez donc le tableau de décision du chapitre 8 pour juger de la faisabilité avant de vous engager.
2. Vue d’ensemble — Ce que signifie arrêter de gérer ses propres mots de passe
2.1 Ce qui pose problème dans la gestion maison
Lorsqu’une application métier gère les mots de passe dans sa propre table utilisateurs, les responsabilités suivantes retombent entièrement sur l’application — c’est-à-dire sur nous, les développeurs.
- Stockage : le choix et la mise en œuvre du schéma de hachage (on trouve encore, aujourd’hui, des tables vieilles de 15 ans qui traînent en MD5 sans sel)
- Exploitation : la prise en charge des demandes de réinitialisation de mot de passe, les verrouillages de compte, la distribution des mots de passe initiaux
- Cycle de vie : la désactivation des comptes lors des départs ou mutations. Avec cinq applications, il faut désactiver le compte cinq fois séparément
- Audit : l’enregistrement et la conservation de qui s’est connecté et quand. L’authentification multifacteur est de fait quasiment impossible à mettre en œuvre
En déléguant l’authentification à Entra ID, ces quatre responsabilités disparaissent du code de l’application et se retrouvent centralisées dans l’administration du tenant. Il suffit de désactiver le compte Entra ID d’une personne qui part pour qu’elle soit immédiatement bloquée dans toutes les applications, et les journaux de connexion sont conservés automatiquement. Pour une organisation qui a déjà déployé Microsoft 365, il n’y a presque plus de raison de continuer à faire tourner sa propre authentification. (Pour les organisations sous Google Workspace qui souhaitent le mécanisme équivalent — faire basculer la connexion Windows elle-même vers un compte Google —, voir « Qu’est-ce que GCPW ? ».)
2.2 Les concepts minimaux — client public et jetons
Sans reprendre l’explication classique d’OAuth 2.0 / OpenID Connect, voici uniquement les concepts nécessaires à l’implémentation dans une application de bureau.
| Concept | Signification pour une application de bureau |
|---|---|
| Client public | Une application — exe, application mobile, etc. — qui ne peut pas conserver de secret (client secret) en sécurité. Elle ne peut obtenir des jetons qu’au nom d’un utilisateur |
| Client confidentiel (confidential client) | Une application telle qu’un serveur web ou un démon, capable de détenir un secret ou un certificat. Une application de bureau n’en fait pas partie |
| Jeton d’ID (ID token) | Un JWT représentant « qui est cette personne ». Il suffit à lui seul si l’on ne veut qu’une fonction de connexion |
| Jeton d’accès (access token) | Un laissez-passer pour appeler une API spécifique (Microsoft Graph ou une API web maison). Il contient la destination (audience) et les scopes |
| Jeton d’actualisation (refresh token) | Un jeton servant à renouveler les deux précédents sans interaction. MSAL le gère automatiquement dans le cache ; l’application ne le voit jamais directement |
La première ligne est la plus importante. Comme un exécutable peut être analysé et décompilé partout où il est distribué, tout « secret » qui y est intégré cesse d’en être un. C’est pourquoi l’application s’inscrit comme un client public fonctionnant sans secret, et l’authentification proprement dite (saisie du mot de passe, MFA) est déléguée à un navigateur ou au broker du système d’exploitation, l’application ne recevant qu’un jeton. Le fait que l’application ne touche jamais au mot de passe de l’utilisateur est le fondement même de cette architecture.
2.3 Le ROPC est une impasse — ce que dit vraiment la documentation
Le réflexe à l’ancienne consiste à se dire : « il suffit de recueillir le nom d’utilisateur et le mot de passe dans notre propre écran de connexion, puis de les faire vérifier en coulisses par Entra ID ». C’est le ROPC (transmission directe du nom d’utilisateur et du mot de passe) : il subsiste dans MSAL.NET sous la forme d’AcquireTokenByUsernamePassword, mais la documentation officielle actuelle est sans ambiguïté.
- Le ROPC destiné aux clients publics est explicitement documenté comme « déprécié en raison d’un risque de sécurité », avec un guide de migration publié vers des flux plus sûrs. 3
- Le ROPC est incompatible avec la MFA et l’accès conditionnel. Un utilisateur pour lequel le tenant impose la MFA sera tout simplement bloqué et incapable de se connecter via ce flux. 2
- Le SSO ne fonctionne pas, les comptes Microsoft personnels ne peuvent pas être utilisés, et les comptes sans mot de passe (FIDO, Authenticator) ne peuvent pas non plus se connecter. 2
- Du côté des API web de Microsoft, la tendance est également à n’accepter que des jetons ayant satisfait la MFA, et la documentation officielle elle-même indique que « les applications qui dépendent du ROPC finiront par être bloquées (locked out) ; les applications de bureau doivent migrer vers une authentification basée sur un broker ». 2
Comme l’obligation de MFA peut être activée à tout moment par une simple configuration côté tenant, adopter le ROPC au motif que « ça fonctionne actuellement » revient à risquer de voir, du jour au lendemain, tous les utilisateurs bloqués. Même si une application existante fonctionne aujourd’hui avec le ROPC, planifiez sa migration. En pratique, seules deux méthodes d’acquisition de jeton sont acceptables pour une application de bureau.
| Flux | Cas d’usage |
|---|---|
| Interactif (broker / navigateur) | Applications GUI classiques. Le choix privilégié |
| Flux de code d’appareil (device code flow) | Environnements où aucun navigateur ne peut s’afficher (console via SSH, etc.). Affiche une URL et un code, et l’utilisateur se connecte depuis le navigateur d’un autre appareil |
3. Inscription de l’application — configuration dans le centre d’administration Entra
Avant d’écrire la moindre ligne de code, il faut inscrire l’application auprès du tenant. Si le développeur ne peut pas le faire lui-même, cette section peut servir telle quelle de document de demande à transmettre au service informatique.
3.1 L’inscription proprement dite
Créez-la depuis [Inscriptions d’applications] → [Nouvelle inscription] dans le centre d’administration Microsoft Entra (entra.microsoft.com). 7
- Nom : il apparaît sur l’écran de consentement et dans les journaux de connexion ; choisissez donc un nom parlant pour le métier, comme « Système de gestion des stocks ».
- Types de comptes pris en charge : pour une application interne, « Comptes dans cet annuaire organisationnel uniquement » (mono-tenant) est le seul choix pertinent. Le multi-tenant ne concerne que les produits distribués à plusieurs organisations.
- Notez l’ID d’application (client) et l’ID d’annuaire (tenant) affichés après l’inscription, et intégrez-les dans la configuration de l’application (aucun des deux n’est une information secrète).
3.2 URI de redirection — choisir la plateforme « Applications mobiles et de bureau »
C’est la déclaration de l’endroit où le jeton est reçu après l’authentification. Sous [Authentification] → [Ajouter une plateforme] → [Applications mobiles et de bureau], enregistrez l’URI correspondant à la méthode d’authentification utilisée. 1
| Méthode d’authentification | URI de redirection à enregistrer |
|---|---|
| Broker WAM (le choix privilégié, chapitre 5) | ms-appx-web://microsoft.aad.brokerplugin/{ID client} |
| Navigateur système | http://localhost |
| Navigateur intégré | https://login.microsoftonline.com/common/oauth2/nativeclient |
Vous n’écrivez jamais ms-appx-web://... (celui de WAM) dans le code MSAL, mais son enregistrement côté inscription de l’application est obligatoire. 8 Compte tenu du repli vers le navigateur qui se produit lorsque WAM n’est pas disponible (chapitre 5), l’approche pragmatique consiste à enregistrer d’emblée les trois URI du tableau ci-dessus. Un point mérite une attention particulière : le comportement de WithDefaultRedirectUri() est dépendant de la plateforme — il se résout vers https://login.microsoftonline.com/common/oauth2/nativeclient sous .NET Framework, et vers http://localhost sous .NET (Core et suivants). 9 Si une application .NET Framework n’a enregistré que ms-appx-web et http://localhost, et que WAM se replie sur le navigateur, vous obtiendrez une erreur d’authentification due à l’incohérence avec nativeclient. Enregistrez les trois URI, ou fixez-en une explicitement avec WithRedirectUri(...). Enregistrer par erreur l’URI sous la plateforme « Web » est un autre piège classique qui produit une erreur d’authentification.
3.3 Autorisations d’API et consentement de l’administrateur
Sous [Autorisations d’API], ajoutez les autorisations déléguées (delegated permission) des API que l’application appelle. Pour une simple connexion avec affichage du profil, l’autorisation User.Read de Microsoft Graph, accordée par défaut, suffit.
Une fois les autorisations ajoutées, faites exécuter [Accorder un consentement administrateur pour (nom du tenant)]. 7 Cela supprime la boîte de dialogue de consentement par utilisateur lors de la première connexion. Dans les tenants où le consentement utilisateur est désactivé, la première connexion s’arrête sur « l’approbation de l’administrateur est requise » en l’absence de consentement administrateur ; en règle générale, pour une application à diffusion interne, complétez le consentement administrateur avant la distribution.
3.4 L’indicateur « Autoriser les flux clients publics »
Le bouton « Autoriser les flux clients publics » dans les paramètres avancés d’Authentification se règle sur « Oui » lorsqu’on utilise un flux qui n’utilise pas d’URI de redirection, comme le flux de code d’appareil ou l’authentification Windows intégrée. 1 Ce n’est pas nécessaire pour le seul mode interactif (navigateur / broker). Notez par ailleurs que cette inscription d’application ne crée ni secret client ni certificat. Avoir la section « Certificats et secrets » vide est l’état correct pour un client public (cette confusion revenant souvent en consultation, nous y revenons au chapitre 9).
4. Implémentation avec MSAL.NET — le schéma de base Silent puis Interactive
Ajoutez Microsoft.Identity.Client via NuGet. Il n’y a réellement qu’un seul schéma d’implémentation à retenir : appelez toujours AcquireTokenSilent en premier, et ne basculez vers le mode interactif que lorsque vous recevez une MsalUiRequiredException. AcquireTokenInteractive est conçu pour ne jamais consulter le cache, donc l’appeler directement affiche l’écran de connexion à chaque fois. 4
using Microsoft.Identity.Client;
public sealed class AuthService
{
private const string ClientId = "ID d'application (client)";
private const string TenantId = "ID d'annuaire (tenant)";
private static readonly string[] Scopes = { "User.Read" };
private readonly IPublicClientApplication _app;
public AuthService()
{
_app = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(AzureCloudInstance.AzurePublic, TenantId)
.WithRedirectUri("http://localhost") // pour le navigateur système
.Build();
// En production, enregistrer ici la persistance du cache de jetons (chapitre 6)
}
public async Task<AuthenticationResult> SignInAsync(IntPtr ownerHwnd)
{
// 1. Toujours essayer d'abord l'acquisition silencieuse avec un compte en cache
var accounts = await _app.GetAccountsAsync();
var account = accounts.FirstOrDefault();
try
{
return await _app.AcquireTokenSilent(Scopes, account)
.ExecuteAsync();
}
catch (MsalUiRequiredException)
{
// 2. N'afficher l'écran de connexion que lorsqu'une interaction est nécessaire.
// Le comportement par défaut de .NET Framework est l'ancien WebView intégré,
// on spécifie donc explicitement la redirection http://localhost = navigateur système
// (.NET 6+ n'utilise de toute façon que le navigateur système)
return await _app.AcquireTokenInteractive(Scopes)
.WithAccount(account)
.WithParentActivityOrWindow(ownerHwnd)
.WithUseEmbeddedWebView(false)
.ExecuteAsync();
}
}
}
L’appelant transmet le handle de la fenêtre propriétaire. Cela évite que la boîte de dialogue d’authentification ne se retrouve cachée derrière la fenêtre de l’application — une précaution obligatoire avec WAM. 5 Autre point : ne pas omettre WithUseEmbeddedWebView(false) dans une application .NET Framework. Le comportement par défaut de l’authentification interactive sous .NET Framework est le WebView intégré, alors que la redirection http://localhost est destinée au navigateur système. (Si la combinaison est incohérente, on se retrouve soit avec un repli vers l’ancien navigateur intégré — qui ne prend en charge ni l’accès conditionnel ni Windows Hello/FIDO —, soit avec une incompatibilité d’URI de redirection.) 10 À partir de .NET 6, il n’y a plus du tout de WebView intégré et c’est toujours le navigateur système qui est utilisé ; cette spécification devient donc redondante, mais reste sans danger.
// WinForms (dans une méthode de Form)
var result = await _authService.SignInAsync(this.Handle);
// WPF
var hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
var result = await _authService.SignInAsync(hwnd);
this.Text = $"Connecté en tant que : {result.Account.Username}";
Voici quelques points à retenir.
- Réutilisez une seule instance d’
IPublicClientApplicationpour toute l’application. Comme le cache est propre à chaque instance, en créer une nouvelle viaCreateà chaque appel empêche l’acquisition silencieuse de fonctionner. MsalUiRequiredExceptionn’est pas une « anomalie » mais un flux de contrôle normal signifiant qu’une interaction est nécessaire. Elle survient au premier lancement, quand le jeton d’actualisation a expiré, ou quand les exigences de l’accès conditionnel changent.- La bonne pratique consiste à appeler
AcquireTokenSilentjuste avant chaque appel d’API. S’il existe un jeton valide en cache, il est renvoyé immédiatement, et il est actualisé automatiquement à l’approche de son expiration. 4 Ne conservez jamais vous-même un jeton d’accès pour en gérer la durée de vie. - Attendre sur le thread UI avec
.Resultou.Wait()provoque un blocage mutuel (deadlock) (voir « Async et le thread d’interface en WPF/WinForms résumés en une page »).
5. Le broker WAM — la configuration recommandée sous Windows
Le code du chapitre 4 ouvre un navigateur, mais sous Windows il existe une méthode encore meilleure. WAM (Web Account Manager) est un broker d’authentification intégré à Windows 10 (1703 et versions ultérieures) et à Windows Server 2019 et versions ultérieures ; la documentation officielle en cite quatre avantages. 5
- Sécurité renforcée : les jetons d’actualisation sont liés à l’appareil, de sorte que même volés, ils sont inutilisables sur un autre poste (protection des jetons). Les améliorations de sécurité continuent d’arriver via les mises à jour du système.
- Prise en charge des fonctionnalités : les fonctions d’authentification intégrées au système et aux services, comme Windows Hello, l’accès conditionnel et les clés FIDO, deviennent disponibles sans code supplémentaire.
- Intégration système : les comptes déjà connectés à Windows apparaissent dans le sélecteur de comptes intégré, si bien que dans la plupart des cas la connexion se fait sans saisie de mot de passe — un SSO de fait.
- Protection des jetons : compatible avec les stratégies de protection des jetons de l’accès conditionnel.
Si les PC de l’entreprise sont joints à Entra (ou en Hybrid Join), l’expérience devient : « lancer l’application → choisir le compte Windows → connexion immédiate », sans jamais saisir de mot de passe où que ce soit.
5.1 Implémentation — WithBroker et le paquet
L’utilisation de WAM nécessite MSAL.NET 4.52.0 ou supérieur et le paquet supplémentaire Microsoft.Identity.Client.Broker. 5 Ajoutez WithBroker au builder du chapitre 4.
using Microsoft.Identity.Client;
using Microsoft.Identity.Client.Broker; // pour WithBroker(BrokerOptions)
var brokerOptions = new BrokerOptions(BrokerOptions.OperatingSystems.Windows)
{
Title = "Système de gestion des stocks" // titre affiché dans le sélecteur de comptes
};
_app = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(AzureCloudInstance.AzurePublic, TenantId)
.WithDefaultRedirectUri()
.WithParentActivityOrWindow(() => _ownerHwnd) // obligatoire avec WAM
.WithBroker(brokerOptions)
.Build();
On peut aussi renforcer d’une ligne le côté acquisition silencieuse. Quand il n’y a pas de compte en cache, passer PublicClientApplication.OperatingSystemAccount permet de tenter une connexion silencieuse avec « le compte actuellement connecté à Windows ». C’est le schéma officiellement recommandé pour obtenir une connexion sans boîte de dialogue dès le tout premier lancement. 8
var accounts = await _app.GetAccountsAsync();
var account = accounts.FirstOrDefault()
?? PublicClientApplication.OperatingSystemAccount;
try
{
return await _app.AcquireTokenSilent(Scopes, account).ExecuteAsync();
}
catch (MsalUiRequiredException)
{
return await _app.AcquireTokenInteractive(Scopes).ExecuteAsync();
}
En parallèle, comme indiqué à la section 3.2, enregistrez ms-appx-web://microsoft.aad.brokerplugin/{ID client} côté inscription de l’application, sous la plateforme « Applications mobiles et de bureau ». 5 L’oublier fait échouer l’authentification interactive avec une erreur de broker. Autre point : le WithDefaultRedirectUri() de l’exemple ci-dessus ne détermine l’URI de redirection que pour le cas où WAM n’est pas disponible et où l’on se replie sur le navigateur, et sa résolution dépend de la plateforme (.NET Framework → nativeclient, .NET → http://localhost). 9 Si les trois URI du tableau de la section 3.2 sont déjà enregistrées, les deux fonctionnent ; si vous souhaitez restreindre l’enregistrement, fixez-le explicitement avec WithRedirectUri(...).
5.2 Les contraintes de WAM — ce qui piège si on ne le sait pas
| Contrainte | Détails |
|---|---|
| OS | Windows 10 (1703)+ / Windows Server 2019+. Sur les versions antérieures, Mac ou Linux, repli automatique sur le navigateur 5 |
| Fournisseur d’identité | Entra ID uniquement. Les autorités Azure AD B2C et AD FS ne sont pas prises en charge (repli sur le navigateur) 5 |
| Contexte d’exécution | Suppose de pouvoir afficher une interface dans une session utilisateur interactive. Les services Windows, le Planificateur de tâches (hors session utilisateur) ou une exécution sous un autre utilisateur via runas génèrent une erreur par conception 5 |
La troisième ligne compte particulièrement. « Ça marche dans l’application avec interface, mais le même code échoue une fois réutilisé dans un traitement batch nocturne » — c’est le comportement attendu, pas un bug. L’exécution sans surveillance est un domaine où il faut séparer la conception vers les autorisations applicatives (client confidentiel) plutôt que de réutiliser un jeton délégué à l’utilisateur. Comme le repli est intégré dans la conception même, MSAL permet d’obtenir « WAM en premier choix, navigateur en secours » en une seule ligne de code.
6. Persister le cache de jetons — ne pas afficher l’écran de connexion à chaque redémarrage
Le cache de jetons de MSAL.NET n’existe qu’en mémoire par défaut, et sur une application de bureau, sa persistance est de la responsabilité de l’application. Sans persistance, AcquireTokenSilent échoue à chaque redémarrage du processus et bascule en connexion interactive. 4 « Tout allait bien pendant le pilote, mais le terrain se plaint de voir l’écran de connexion apparaître chaque matin » — c’est presque toujours la cause de ce type de retour.
La recommandation officielle consiste à utiliser la bibliothèque de cache multiplateforme Microsoft.Identity.Client.Extensions.Msal (NuGet). 6
using Microsoft.Identity.Client.Extensions.Msal;
var storageProperties = new StorageCreationPropertiesBuilder(
"msal_cache.dat",
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"KomuraSoft", "InventoryApp"))
.Build();
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties);
cacheHelper.RegisterCache(_app.UserTokenCache); // à enregistrer une fois, juste après Build()
Sous Windows, le cache est stocké chiffré. L’exemple d’implémentation maison présenté dans la documentation officielle chiffre le jeton avec ProtectedData (DPAPI, DataProtectionScope.CurrentUser) avant de l’enregistrer dans un fichier ; Extensions.Msal se positionne comme une bibliothèque de qualité production construite sur cette même idée. 6 Le principe « protéger les secrets propres à chaque utilisateur avec un DPAPI à portée utilisateur » est le même que celui évoqué pour les fichiers de configuration dans « Stockage des informations sensibles dans une application Windows - éviter les paramètres en clair avec DPAPI ». Traitez une implémentation maison qui enregistre le cache de jetons en JSON en clair avec la même gravité qu’un stockage en clair d’une chaîne de connexion.
Trois points d’attention pour l’exploitation.
- La persistance du cache est nécessaire même en utilisant WAM. MSAL continue de stocker le jeton d’ID et les métadonnées de compte dans son propre cache. 8
- L’emplacement de stockage type est
%LOCALAPPDATA%\NomEntreprise\NomApplication. En raison de la liaison propre à DPAPI, le déchiffrement échoue sur un autre PC ou pour un autre utilisateur, mais la seule conséquence est l’échec de l’acquisition silencieuse suivi d’une nouvelle connexion — aucun dommage réel. - Implémentez la « déconnexion » en énumérant les comptes avec
GetAccountsAsyncpuis en les supprimant avecRemoveAsync; il n’est pas nécessaire de supprimer le fichier de cache. Toutefois,RemoveAsyncne supprime que le cache local de MSAL — les sessions côté WAM, navigateur ou connexion Windows restent intactes. Comme la prochaine connexion interactive peut reconnecter silencieusement le même compte, si vous devez permettre un véritable changement de compte sur un PC partagé, concevez cela explicitement : ajoutezWithPrompt(Prompt.SelectAccount)àAcquireTokenInteractivepour toujours afficher l’écran de sélection de compte, ou, selon vos besoins, combinez aussi avec le point de terminaison de déconnexion du tenant. Distinguez clairement « supprimer le cache local » et « une véritable déconnexion ».
7. Que faire du jeton obtenu — trois configurations
Une fois l’authentification réussie, son usage se répartit en trois schémas. Le niveau visé détermine la configuration supplémentaire nécessaire.
| Configuration | Jeton utilisé | Ce qu’il faut en plus |
|---|---|---|
| (1) Connexion uniquement | Jeton d’ID (AuthenticationResult.Account / ClaimsPrincipal) |
Rien (User.Read suffit) |
| (2) Appeler Microsoft Graph | Jeton d’accès pour Graph | Autorisations Graph et consentement correspondant aux API visées |
| (3) Protéger une API web maison | Jeton d’accès pour l’API maison | Inscription d’application et exposition de scope côté API, plus validation du jeton côté API |
7.1 Configuration « connexion uniquement » — commencer le plus petit possible
Si l’objectif est simplement « remplacer notre propre vérification de mot de passe, sans appeler d’API cloud », il suffit de confronter les informations de compte du résultat de connexion à la table de droits interne de l’application. Remplacez la clé de la table users par l’ID d’objet Entra (qui reste stable même si l’UPN change, par exemple après un changement de nom de famille) et supprimez la colonne mot de passe. Comme cela permet de remplacer uniquement l’authentification sans changer la conception de la base locale, c’est la configuration la plus facile à recommander comme premier pas.
7.2 Appeler Microsoft Graph
En envoyant directement le jeton d’accès User.Read à Microsoft Graph, on peut récupérer le profil ou la photo de l’utilisateur connecté.
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", result.AccessToken);
var me = await http.GetStringAsync("https://graph.microsoft.com/v1.0/me");
Pour étendre l’usage au calendrier, à l’envoi de mails, aux notifications Teams, etc., ajoutez l’autorisation correspondante (Mail.Send, etc.) et redemandez le consentement administrateur. Faire reposer sur Graph les mails de notification envoyés depuis une application interne s’inscrit bien dans la même logique que celle abordée dans « Concevoir un envoi de masse d’e-mails pour les PME sans dépendre d’un service spécifique ».
7.3 Protéger une API web maison — jusqu’à la validation de l’audience et des scopes
Si l’application de bureau appelle l’API web de l’entreprise, il faut également créer une inscription d’application distincte côté API, exposer un scope tel que api://{ID client de l'API}/access_as_user, et faire en sorte que le côté bureau demande un jeton avec ce scope. Ce qui compte côté API, c’est que la documentation officielle précise explicitement que l’attribut [Authorize] seul ne suffit pas. 11 Il y a trois niveaux à valider.
- Signature et émetteur : s’agit-il d’un JWT émis par le bon tenant Entra ID (avec ASP.NET Core + Microsoft.Identity.Web, c’est le middleware qui s’en charge) ?
- Audience (
aud) : la destination du jeton est-elle cette API elle-même ? Ne laissez pas un jeton destiné à Graph être réutilisé sur votre propre API. - Scope (revendication
scp) : contient-il le scope attendu ? Avec Microsoft.Identity.Web, cela peut être déclaré via l’attribut[RequiredScope("access_as_user")]11
Omettre les points 2 et 3 aboutit à « une API que traverse n’importe qui, du moment que le jeton ressemble à un jeton Entra ». Faites-en un point de revue de conception, au même titre que les rubriques communication et validation des entrées de « Liste de contrôle minimale pour la sécurité du développement d’applications Windows ».
8. Le jugement d’adoption — faut-il ajouter l’authentification Entra à un outil purement interne ?
Faut-il l’ajouter à toutes les applications internes ? Pas nécessairement. Voici un tableau de décision.
| Situation | Recommandation | Raison |
|---|---|---|
| Microsoft 365 / Entra ID déployé dans toute l’entreprise + l’application a déjà une notion de connexion | Adoptez | Toute la dette liée à la gestion maison des mots de passe disparaît. Coût d’implémentation faible |
| L’application appelle une API web maison ou des ressources cloud | Adoptez | Un socle d’authentification est indispensable pour protéger l’API. Plus fiable que d’inventer son propre schéma de jeton |
| Il existe une exigence d’audit (traçabilité de qui a utilisé quoi et quand, MFA obligatoire) | Adoptez | Les journaux de connexion et l’accès conditionnel sont centralisés côté tenant |
| Outil monofonction sans notion de connexion (outil de conversion, visionneuse, etc.) | Pas nécessaire | Aucune raison d’ajouter l’authentification. La connexion Windows suffit déjà |
| Fonctionne dans un environnement totalement hors ligne (chaîne de production isolée, PC emporté hors site) | Pas faisable, ou nécessite une conception dédiée | La première connexion et le renouvellement de jeton nécessitent tous deux le réseau |
| Entra ID non déployé (AD on-premise seul, ou Google Workspace seul) | Chercher une autre solution | Pour le premier cas, l’authentification AD (authentification Windows intégrée) ; pour le second, un mécanisme côté Google est plus naturel |
Soyez particulièrement vigilant sur l’exigence hors ligne. AcquireTokenSilent peut renvoyer un jeton même hors ligne tant que le jeton d’accès en cache reste valide (empiriquement, un peu plus d’une heure), mais une fois expiré, son renouvellement exige le réseau. Avant l’adoption, il faut confronter cette hypothèse de durée de vie aux schémas d’utilisation réels sur le terrain.
9. Les pièges opérationnels — les questions qui arrivent après le déploiement
Le déploiement n’est pas la fin de l’histoire : des questions reviennent régulièrement en phase d’exploitation. En voici un aperçu, à l’avance.
- « Ça marchait encore hier, et soudain je ne peux plus me connecter » : le premier suspect est un changement de la politique d’accès conditionnel. Lorsque le service informatique active par exemple « bloquer les appareils non enregistrés », la connexion commence à échouer alors que l’application elle-même n’a rien changé. Le moyen le plus rapide de diagnostiquer est de consulter les journaux de connexion du centre d’administration Entra pour voir la raison d’erreur de l’utilisateur concerné. Une configuration WAM renforce la capacité à répondre aux exigences des politiques, ce qui réduit d’elle-même ce type de friction. 5
- « On a reçu une notification comme quoi un secret va expirer, cette application est-elle concernée ? » : les clients publics n’ont, par nature, ni secret ni certificat, donc rien n’expire. Si cette question se pose, c’est soit une confusion avec l’inscription d’un client confidentiel, soit que quelqu’un a créé un secret inutile sur l’inscription du client public (dans ce dernier cas, il peut être supprimé sans problème). Le fait qu’un incident d’arrêt dû à l’expiration d’un secret ne puisse structurellement pas se produire est un avantage caché de cette configuration.
- « Au premier lancement, le message “l’approbation de l’administrateur est requise” s’affiche » : c’est un consentement administrateur manquant, comme décrit à la section 3.3. Même en ajoutant une autorisation après coup, le même message réapparaît tant que le consentement de l’ajout n’a pas été redonné.
- « Intégré dans un traitement batch nocturne, ça ne fonctionne pas » : comme indiqué à la section 5.2, WAM suppose une session interactive. Concevez le traitement sans surveillance autour des autorisations applicatives, plutôt qu’en réutilisant un jeton délégué à l’utilisateur.
- Distribution et mises à jour : MSAL fait l’objet de correctifs fréquents, il faut donc un mécanisme capable de diffuser les mises à jour de la bibliothèque sur tous les postes. Réfléchissez-y en parallèle de la vérification du canal de mise à jour évoquée dans « Conception de la sécurité des mises à jour automatiques - pourquoi HTTPS seul ne suffit pas ».
10. Résumé
La prise en charge de l’authentification Entra ID dans une application WinForms / WPF se résume aux six points suivants.
- L’objectif en soi est d’arrêter de gérer ses propres mots de passe. Le stockage, les réinitialisations, la gestion des départs et l’audit se centralisent côté tenant
- Une application de bureau est un client public. Elle ne peut pas détenir de secret, et n’en a pas besoin
- Le ROPC est en voie de dépréciation. Ne créez pas de nouvel écran qui recueille directement le nom d’utilisateur et le mot de passe
- L’implémentation ne connaît qu’un seul schéma : celui de MSAL.NET,
AcquireTokenSilent→AcquireTokenInteractive - Sous Windows, le broker WAM (
WithBroker) apporte le SSO ainsi que la prise en charge de l’accès conditionnel et de Windows Hello - Intégrez dès le départ la persistance du cache de jetons (Extensions.Msal / protection DPAPI)
Avec la configuration minimale « ne remplacer que la connexion » (section 7.1), l’impact sur une application existante peut se limiter à l’écran de connexion et à la table utilisateurs, et la modification tient souvent en quelques jours de travail. En revanche, dès que l’accès conditionnel ou des exigences hors ligne entrent en jeu, il faut des décisions de conception qui tiennent compte à la fois de la configuration côté tenant et de la réalité du métier. Si vous hésitez sur la configuration à viser pour votre application, ou sur la manière de découper les étapes de migration depuis une authentification maison, nous pouvons vous accompagner.
Articles connexes
- Qu’est-ce que GCPW ? — Gérer la connexion Windows avec l’authentification Google
- Stockage des informations sensibles dans une application Windows - éviter les paramètres en clair avec DPAPI
- Liste de contrôle minimale pour la sécurité du développement d’applications Windows
- Conception de la sécurité des mises à jour automatiques - pourquoi HTTPS seul ne suffit pas
Domaines de conseil associés
Komura Software LLC prend en charge l’intégration de l’authentification Entra ID dans des applications WinForms / WPF existantes (conception de l’inscription d’application, implémentation MSAL.NET, planification de la migration depuis une authentification maison), les revues de conception de la validation des jetons pour des API web maison, ainsi que le diagnostic des incidents de connexion liés à l’accès conditionnel.
- Développement d’applications Windows
- Conseil technique et revue de conception
- Réutilisation des actifs existants et accompagnement à la migration
- Contact
Références
-
Microsoft Learn, Desktop app that calls web APIs: Code configuration. Sur les URI de redirection pour les applications de bureau (plateforme mobile et de bureau, nativeclient / localhost) et la signification du paramètre « Autoriser les flux clients publics ». ↩ ↩2 ↩3
-
Microsoft Learn, Microsoft identity platform and OAuth 2.0 Resource Owner Password Credentials. Sur les raisons de ne pas utiliser le ROPC, son incompatibilité avec la MFA entraînant un blocage, la tendance à l’exclusion des applications dépendantes du ROPC, et la recommandation pour les applications de bureau de migrer vers une authentification basée sur un broker. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Desktop app that calls web APIs: Acquire a token using username and password. Sur la dépréciation du flux nom d’utilisateur/mot de passe (ROPC) pour risque de sécurité, l’orientation vers un guide de migration, et son absence de prise en charge de la MFA, de l’accès conditionnel et du SSO. ↩ ↩2
-
Microsoft Learn, Get a token from the token cache using MSAL.NET. Sur le schéma recommandé consistant à appeler d’abord AcquireTokenSilent puis à basculer vers le mode interactif en cas de MsalUiRequiredException, le renouvellement automatique via le cache et le jeton d’actualisation, et l’effacement du cache par suppression d’un compte. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Using MSAL.NET with Web Account Manager (WAM). Sur les avantages du broker (sécurité renforcée, prise en charge de Windows Hello / de l’accès conditionnel / de FIDO, sélecteur de comptes, protection des jetons), les exigences de MSAL.NET 4.52.0+ et du paquet Microsoft.Identity.Client.Broker, le caractère obligatoire de WithBroker et du handle de fenêtre parente, l’URI de redirection ms-appx-web, les OS pris en charge et le comportement de repli, ainsi que la nécessité d’une session interactive. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, Token cache serialization. Sur la recommandation pour les applications de bureau d’utiliser le cache multiplateforme de Microsoft.Identity.Client.Extensions.Msal, l’utilisation de MsalCacheHelper, et l’exemple de sérialisation maison via ProtectedData (DPAPI, portée CurrentUser). ↩ ↩2 ↩3
-
Microsoft Learn, Register an application with the Microsoft identity platform. Sur la procédure d’inscription d’application dans le centre d’administration Entra, le choix des types de comptes pris en charge, l’obtention de l’ID client, et le consentement de l’administrateur. ↩ ↩2
-
Microsoft Learn, Desktop app that calls web APIs: Acquire a token by using WAM. Sur la nécessité de la persistance du cache de jetons même en utilisant WAM, le schéma recommandé de connexion silencieuse via OperatingSystemAccount, et la configuration de l’URI de redirection côté inscription de l’application. ↩ ↩2 ↩3
-
Microsoft Learn, Default reply URI. Sur la dépendance à la plateforme de l’URI de redirection définie par WithDefaultRedirectUri (https://login.microsoftonline.com/common/oauth2/nativeclient pour le bureau .NET Framework, http://localhost pour .NET Core). ↩ ↩2
-
Microsoft Learn, Using web browsers (MSAL.NET). Sur le tableau de compatibilité des navigateurs par framework (.NET Framework 4.6.2+ utilise l’intégré par défaut, .NET 6+ n’utilise que le navigateur système), la nécessité d’une URI de redirection http://localhost pour le navigateur système, et la bascule via WithUseEmbeddedWebView. ↩
-
Microsoft Learn, Protected web API: Verify scopes and app roles. Sur le fait que l’attribut [Authorize] seul ne suffit pas, la nécessité de valider la revendication scp (le scope), et la validation déclarative via l’attribut RequiredScope de Microsoft.Identity.Web. ↩ ↩2
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Icônes de la zone de notification et notifications toast dans les applications Windows — les pièges de NotifyIcon et comment choisir la bonne AppNotification
Un guide pratique pour maintenir une application Windows métier résidente dans la zone de notification (system tray) et avertir l'utilisa...
Tests UI automatisés pour applications de bureau Windows — le fonctionnement de UI Automation et la construction de tests robustes avec FlaUI
Un guide pratique des tests UI automatisés pour applications WinForms/WPF, en partant du fonctionnement de Windows UI Automation (l'arbor...
Le support du haut DPI dans WPF — pourquoi l'affichage reste flou et baveux malgré une application « censée résister au DPI », et comment y remédier
WPF met en page en DIP (1/96 de pouce) et est System DPI Aware dès le départ, mais déplacer une fenêtre vers un moniteur au DPI différent...
La prise en charge du haut DPI dans WinForms — pourquoi l'interface devient floue ou se casse sur les moniteurs 4K, et solutions concrètes
Cet article explique pourquoi les applications WinForms deviennent floues ou voient leur mise en page se casser sur les moniteurs 4K, à p...
CI/CD pratique pour les applications WinForms / WPF — Automatiser du build à la signature et à la distribution avec GitHub Actions
Guide pratique pour mettre en place le CI/CD des applications WinForms / WPF avec GitHub Actions. Couvre un YAML minimal de build+tests s...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Thread UI et minuteries
Thread UI WPF / WinForms, flux asynchrones, Dispatcher et temporisation.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Développement d'applications Windows
Applications métier, intégration d'équipements et outils de communication, des besoins au développement.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Quel est l'intérêt d'ajouter l'authentification Entra ID à une application WinForms/WPF ?
- Déléguer l'authentification à Entra ID fait que le stockage des mots de passe, la prise en charge des réinitialisations, la désactivation des comptes des personnes qui quittent l'entreprise et l'audit des connexions cessent d'être des responsabilités de l'application et se retrouvent centralisés dans l'administration du tenant. Il suffit de désactiver le compte Entra ID d'une personne qui part pour qu'elle soit immédiatement bloquée dans toutes les applications connectées. Les défenses côté tenant telles que l'authentification multifacteur, l'accès conditionnel et les journaux de connexion s'étendent automatiquement à vos applications internes. La mise en œuvre tient dans la bibliothèque MSAL.NET et quelques dizaines de lignes de code.
- Peut-on conserver un écran de connexion maison qui recueille le nom d'utilisateur et le mot de passe (ROPC) ?
- Non — il ne faut pas adopter le ROPC pour un nouveau développement. Microsoft documente officiellement ce flux comme déprécié en raison d'un risque de sécurité, et il est incompatible avec la MFA et l'accès conditionnel : les utilisateurs soumis à une politique de MFA sont tout simplement bloqués à la connexion. Il casse également le SSO et ne peut pas gérer les comptes sans mot de passe comme les clés FIDO. Une application de bureau doit à la place utiliser une authentification interactive via un broker ou un navigateur, avec un repli sur le flux de code d'appareil uniquement lorsqu'aucun navigateur ne peut être affiché.
- Qu'est-ce que le broker WAM et pourquoi est-il recommandé sous Windows ?
- WAM (Web Account Manager) est un broker d'authentification intégré à Windows 10 (1703 et versions ultérieures) et à Windows Server 2019 et versions ultérieures. L'activer avec une seule ligne, WithBroker, apporte le SSO avec le compte déjà connecté à Windows, la prise en charge de Windows Hello, de l'accès conditionnel et des clés FIDO, ainsi que des jetons d'actualisation liés à l'appareil qui ne peuvent pas être réutilisés sur une autre machine. Cela nécessite MSAL.NET 4.52.0 ou supérieur, le paquet Microsoft.Identity.Client.Broker, et l'enregistrement de l'URI de redirection de broker ms-appx-web sur l'inscription de l'application. Sur les systèmes non pris en charge, le repli sur le navigateur se fait automatiquement.
- Pourquoi l'écran de connexion apparaît-il à chaque redémarrage de mon application ?
- Le cache de jetons de MSAL.NET n'existe qu'en mémoire par défaut, donc sur le bureau, l'application doit elle-même le persister. Sans persistance, AcquireTokenSilent échoue à chaque redémarrage du processus et bascule sur une connexion interactive. La recommandation officielle est la bibliothèque Microsoft.Identity.Client.Extensions.Msal, qui stocke le cache chiffré avec un DPAPI à portée utilisateur sous Windows. Notez que la persistance du cache reste nécessaire même en utilisant le broker WAM, car MSAL conserve le jeton d'ID et les métadonnées de compte dans son propre cache.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.
Liens publics