Connexion sur l’application monopage en utilisant un flux implicite OAuth 2.0 dans Azure Active Directory B2C
De nombreuses applications modernes disposent d’un serveur frontal d’application monopage (SPA) écrit principalement en JavaScript. Souvent, l’application est écrite à l’aide d’un framework comme React, Angular ou Vue.js. Les SPA et d’autres applications JavaScript qui s’exécutent principalement dans un navigateur présentent certaines problématiques supplémentaires pour l’authentification :
Les caractéristiques de sécurité de ces applications sont différentes de celles des applications web traditionnelles basées sur serveur.
Beaucoup de serveurs d’autorisation et de fournisseurs d’identité ne prennent pas en charge les demandes de partage des ressources cross-origin (CORS).
Chacune des redirections à partir de l’application du navigateur plein écran peut perturber l’expérience utilisateur.
La méthode recommandée pour prendre en charge les applications monopages est le flux de code d’autorisation OAuth 2.0 (avec PKCE).
Certaines infrastructures, telles que MSAL.js 1.x, ne prennent en charge que le flux d’octroi implicite. Dans ces cas, Azure Active Directory B2C (Azure AD B2C) prend en charge le flux d’octroi implicite de l’autorisation OAuth 2.0. Le flux est décrit dans la section 4.2 de la spécification OAuth 2.0. Dans ce flux implicite, l’application reçoit des jetons directement du point de terminaison d’autorisation Azure AD B2C, sans exécuter d’échanges de serveur à serveur. L’intégralité de la logique d’authentification et de la gestion des sessions est effectuée sur le client JavaScript, à l’aide d’une redirection de page ou d’une fenêtre contextuelle.
Azure AD B2C étend le flux implicite OAuth 2.0 standard au-delà de la simple authentification et de la simple autorisation. Azure AD B2C introduit le paramètre de stratégie. Avec le paramètre de stratégie, vous pouvez utiliser OAuth 2.0 pour ajouter des stratégies à votre application, telles que des flux d’utilisateur d’inscription, de connexion et de gestion des profils. Dans les exemples de requêtes HTTP de cet article, nous utilisons {tenant}.onmicrosoft.com à des fins d’illustration. Remplacez {tenant}
par le nom de votre locataire, si vous en avez un. En outre, vous devez avoir créé un flux utilisateur.
Nous utilisons la figure suivante pour illustrer le déroulement de la connexion implicite. Chaque étape est décrite en détail plus loin dans l’article.
Envoi de demandes d’authentification
Lorsque votre application web a besoin d’authentifier l’utilisateur et d’exécuter un flux utilisateur, elle peut diriger l’utilisateur vers le point de terminaison /authorize
d’Azure AD B2C. L’utilisateur prend des mesures en fonction du flux utilisateur.
Dans cette requête, le client désigne les autorisations qu'il doit obtenir de l'utilisateur dans le paramètre scope
ainsi que le flux utilisateur à exécuter. Pour avoir une idée du fonctionnement de la requête, collez-la dans un navigateur et exécutez-la. Remplacez :
{tenant}
par le nom de votre locataire Azure AD B2C.90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
par l’ID de l’application que vous avez inscrite dans votre locataire.{policy}
par le nom d’une stratégie que vous avez créée dans votre locataire, par exempleb2c_1_sign_in
.
GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=id_token+token
&redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
&response_mode=fragment
&scope=openid%20offline_access
&state=arbitrary_data_you_can_receive_in_the_response
&nonce=12345
Les paramètres de la requête HTTP GET sont expliqués dans le tableau ci-dessous.
Paramètre | Obligatoire | Description |
---|---|---|
{tenant} | Oui | Nom de votre locataire Azure AD B2C |
{policy} | Oui | Nom du flux utilisateur que vous souhaitez exécuter. Spécifiez le nom d'un flux utilisateur créé dans votre locataire Azure AD B2C. Par exemple : b2c_1_sign_in , b2c_1_sign_up ou b2c_1_edit_profile . |
client_id | Oui | ID d’application que le portail Azure a affecté à votre application. |
response_type | Oui | Doit inclure id_token pour la connexion à OpenID Connect. Il peut également inclure le type de réponse token . Si vous utilisez token , votre application peut recevoir immédiatement un jeton d’accès du point de terminaison d’autorisation sans avoir à effectuer une deuxième demande au point de terminaison d’autorisation. Si vous utilisez le type de réponse token , le paramètre scope doit contenir une étendue indiquant la ressource pour laquelle le jeton doit être émis. |
redirect_uri | Non | L’URI de redirection de votre application, vers lequel votre application peut envoyer et recevoir des réponses d’authentification. Il doit correspondre exactement à l’un des URI de redirection que vous avez ajoutés à une application enregistrée dans le portail, sauf qu’il doit être encodé au format URL. |
response_mode | Non | Spécifie la méthode à utiliser pour renvoyer le jeton résultant à votre application. Pour les flux implicites, utilisez fragment . |
scope | Oui | Une liste d’étendues séparées par des espaces. Une valeur d’étendue unique indique à Microsoft Entra ID les deux autorisations qui sont demandées. L’étendue openid indique une autorisation pour connecter l’utilisateur et obtenir des données relatives à l’utilisateur sous la forme de jetons d’ID. L’étendue offline_access est facultative pour les applications Web. Elle indique que votre application a besoin d’un jeton d’actualisation pour un accès durable aux ressources. |
state | Non | Valeur incluse dans la demande qui est également retournée dans la réponse de jeton. Il peut s’agir d’une chaîne de n’importe quel contenu que vous voulez utiliser. Généralement, une valeur unique générée de manière aléatoire est utilisée, de façon à empêcher les attaques par falsification de requête intersites. La valeur d’état est également utilisée pour coder les informations sur l’état de l’utilisateur dans l’application avant la requête d’authentification, comme la page sur laquelle il était positionné ou le flux utilisateur en cours d’exécution. |
nonce | Oui | Une valeur incluse dans la demande (générée par l’application) qui est incluse dans le jeton d’ID résultant en tant que revendication. L’application peut ensuite vérifier cette valeur pour atténuer les attaques par relecture de jetons. En général, la valeur est une chaîne unique aléatoire qui peut être utilisée pour identifier l’origine de la demande. |
prompt | Non | Type d’interaction utilisateur demandée. Actuellement, la seule valeur possible est login . Ce paramètre force l’utilisateur à entrer ses informations d’identification pour cette demande. L’authentification unique ne prend pas effet. |
Il s’agit de la partie interactive du flux. Il est demandé à l’utilisateur d’effectuer le flux de travail de la stratégie. L’utilisateur peut avoir à entrer son nom d’utilisateur et son mot de passe, à se connecter avec une identité sociale, à s’inscrire à un compte local ou à suivre n’importe quelle autre étape. Les actions de l’utilisateur dépendent de la façon dont le flux d’utilisateur est défini.
Une fois que l’utilisateur a terminé le flux d’utilisateur, Azure AD B2C renvoie une réponse à votre application avec la valeur redirect_uri
. Il utilise la méthode spécifiée dans le paramètre response_mode
. La réponse est exactement la même pour chacun des scénarios d’actions utilisateur, indépendamment du flux d’utilisateur exécuté.
Réponse correcte
Une réponse correcte qui utilise response_mode=fragment
et response_type=id_token+token
est semblable à ceci (des sauts de ligne ont été insérés pour une meilleure lisibilité) :
GET https://aadb2cplayground.azurewebsites.net/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&token_type=Bearer
&expires_in=3599
&scope="90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6 offline_access",
&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=arbitrary_data_you_sent_earlier
Paramètre | Description |
---|---|
access_token | Le jeton d’accès que l’application a demandé à Azure AD B2C. |
token_type | Valeur du type de jeton. Le seul type de jeton pris en charge par Azure AD B2C est le jeton porteur. |
expires_in | Durée de validité du jeton d’accès (en secondes). |
scope | Étendues de validité du jeton. Vous pouvez également utiliser des étendues pour mettre en cache des jetons pour une utilisation ultérieure. |
id_token | Le jeton d'ID que l’application a demandé. Vous pouvez utiliser le jeton d'ID pour vérifier l’identité de l’utilisateur et démarrer une session avec lui. Pour plus d’informations sur les jetons d’ID et leur contenu, consultez les Informations de référence sur les jetons Azure AD B2C. |
state | Si un paramètre state est inclus dans la demande, la même valeur doit apparaître dans la réponse. L’application doit vérifier que les valeurs state de la demande et de la réponse sont identiques. |
Réponse d’erreur
Les réponses d’erreur peuvent également être envoyées à l’URI de redirection, pour que l’application puisse les traiter de façon appropriée :
GET https://aadb2cplayground.azurewebsites.net/#
error=access_denied
&error_description=the+user+canceled+the+authentication
&state=arbitrary_data_you_can_receive_in_the_response
Paramètre | Description |
---|---|
error | Code utilisé pour classer les types d’erreurs qui se produisent. |
error_description | Un message d’erreur spécifique qui peut vous aider à identifier la cause principale d’une erreur d’authentification. |
state | Si un paramètre state est inclus dans la demande, la même valeur doit apparaître dans la réponse. L’application doit vérifier que les valeurs state de la demande et de la réponse sont identiques. |
Validation du jeton d’ID
La réception d’un jeton d’ID n’est pas suffisante pour authentifier l’utilisateur. Validez la signature du jeton d’ID et vérifiez les revendications du jeton selon les exigences de votre application. Azure AD B2C utilise les jetons Web JSON (JWT) et le chiffrement de clés publiques pour signer les jetons et vérifier leur validité.
Il existe de nombreuses bibliothèques open source pour valider les jetons JWT en fonction du langage que vous préférez utiliser. Nous vous recommandons d’explorer ces bibliothèques open source plutôt que d’implémenter votre propre logique de validation. Vous pouvez utiliser les informations de cet article pour découvrir comment utiliser correctement ces bibliothèques.
Azure AD B2C a un point de terminaison des métadonnées OpenID Connect. Une application peut utiliser le point de terminaison pour extraire des informations sur Azure AD B2C lors de l’exécution. Ces informations incluent les points de terminaison, le contenu des jetons et les clés de signature de jetons. Il existe un document de métadonnées JSON pour chaque flux d’utilisateur dans votre locataire Azure AD B2C. Par exemple, le document de métadonnées pour un flux d’utilisateurs nommé b2c_1_sign_in
dans un locataire fabrikamb2c.onmicrosoft.com
se trouve à l’adresse suivante :
https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/v2.0/.well-known/openid-configuration
Une des propriétés de ce document de configuration est jwks_uri
. La valeur du même flux d’utilisateur serait :
https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/discovery/v2.0/keys
Pour déterminer le flux d’utilisateur utilisé pour signer un jeton d’ID (et l’emplacement d’où extraire les métadonnées), toutes les options suivantes sont possibles :
Le nom du flux d’utilisateur est inclus dans la revendication
acr
deid_token
. Pour plus d’informations sur la façon d’analyser les revendications à partir d’un jeton d’ID, consultez Informations de référence sur les jetons Azure AD B2C.Encodez le flux d’utilisateur dans la valeur du paramètre
state
lorsque vous émettez la demande, puis de décoder le paramètrestate
pour déterminer quel flux d’utilisateur a été utilisé.
Après avoir acquis le document de métadonnées auprès du point de terminaison de métadonnées OpenID Connect, vous pouvez utiliser les clés publiques RSA 256 (qui se trouvent sur ce point de terminaison) pour valider la signature du jeton d’ID. Il peut y avoir plusieurs clés répertoriées sur ce point de terminaison, chacune étant identifiée par un kid
. L’en-tête de id_token
contient également une revendication de kid
. Il indique laquelle de ces clés a été utilisée pour signer le jeton d’ID. Pour plus d’informations, notamment sur la validation des jetons, consultez les informations de référence sur les jetons d’Azure AD B2C.
Après la validation de la signature du jeton d’ID, plusieurs revendications nécessitent une vérification. Par exemple :
Validez la revendication
nonce
afin d’empêcher les attaques par relecture de jetons. Sa valeur doit correspondre à ce que vous avez spécifié dans la requête de connexion.Validez la revendication
aud
pour vérifier que le jeton d’ID a été émis pour votre application. Sa valeur doit correspondre à l’ID d’application de votre application.Validez les revendications
iat
etexp
pour vérifier que le jeton d’ID n’est pas expiré.
Plusieurs autres validations à effectuer sont décrites en détail dans les spécifications principales d’OpenID Connect. En fonction de votre scénario, vous pouvez également valider des revendications supplémentaires. Voici quelques validations courantes :
Vérifier que l’utilisateur ou l’organisation s’est inscrit pour l’application.
Vérifier que l’utilisateur dispose de l’autorisation et des privilèges appropriés.
Vérifier qu’un certain niveau d’authentification a été atteint, par exemple en utilisant l’authentification multifacteur Microsoft Entra.
Pour plus d’informations sur les revendications dans un jeton d’ID, consultez les Informations de référence sur les jetons Azure AD B2C.
Une fois que vous avez validé le jeton d’ID, vous pouvez démarrer une session avec l’utilisateur. Dans votre application, utilisez les revendications du jeton d’ID pour obtenir des informations sur l’utilisateur. Ces informations peuvent être utilisées pour l’affichage, les enregistrements, les autorisations, etc.
Obtenir des jetons d’accès
Si la seule chose que doit faire votre application web est exécuter des flux d’utilisateur, vous pouvez ignorer les quelques sections suivantes. Les informations des sections suivantes s’appliquent uniquement aux applications web qui doivent effectuer des appels authentifiés à une API web et qui sont protégées par Azure AD B2C lui-même.
Maintenant que vous avez connecté l’utilisateur à votre SPA, vous pouvez obtenir des jetons d’accès pour appeler des API web sécurisées par Microsoft Entra ID. Même si vous avez déjà reçu un jeton en utilisant le type de réponse token
, vous pouvez utiliser cette méthode pour acquérir des jetons pour des ressources supplémentaires sans avoir à demander à l’utilisateur de se reconnecter.
Dans le flux d’une application web standard, vous effectuez une demande au point de terminaison /token
. Cependant, le point de terminaison ne prend pas en charge les requêtes CORS : il n’est donc pas possible d’effectuer des appels AJAX pour obtenir un jeton d’actualisation. Au lieu de cela, vous pouvez utiliser le flux implicite d’un élément IFrame HTML masqué pour obtenir de nouveaux jetons pour d’autres API web. Voici un exemple, avec des sauts de ligne pour une meilleure lisibilité :
https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=token
&redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
&scope=https%3A%2F%2Fapi.contoso.com%2Ftasks.read
&response_mode=fragment
&state=arbitrary_data_you_can_receive_in_the_response
&nonce=12345
&prompt=none
Paramètre | Requis ? | Description |
---|---|---|
{tenant} | Obligatoire | Nom de votre locataire Azure AD B2C |
{policy} | Obligatoire | Flux utilisateur à exécuter. Spécifiez le nom d'un flux utilisateur créé dans votre locataire Azure AD B2C. Par exemple : b2c_1_sign_in , b2c_1_sign_up ou b2c_1_edit_profile . |
client_id | Obligatoire | ID d’application affecté à votre application dans le portail Azure. |
response_type | Obligatoire | Doit inclure id_token pour la connexion à OpenID Connect. Il peut également inclure le type de réponse token . Si vous utilisez token ici, votre application peut recevoir immédiatement un jeton d’accès du point de terminaison d’autorisation, sans avoir à effectuer une deuxième demande au point de terminaison d’autorisation. Si vous utilisez le type de réponse token , le paramètre scope doit contenir une étendue indiquant la ressource pour laquelle le jeton doit être émis. |
redirect_uri | Recommandé | L’URI de redirection de votre application, vers lequel votre application peut envoyer et recevoir des réponses d’authentification. Il doit correspondre exactement à un des URI de redirection inscrits dans le portail, sauf qu’il doit être codé dans une URL. |
scope | Obligatoire | Une liste d’étendues séparées par des espaces. Pour obtenir des jetons, incluez toutes les étendues dont vous avez besoin pour la ressource concernée. |
response_mode | Recommandé | Spécifie la méthode utilisée pour envoyer le jeton résultant à votre application. Pour des flux implicites, utilisez fragment . Deux autres modes peuvent être spécifiés, query et form_post , mais ils ne fonctionnent pas dans le flux implicite. |
state | Recommandé | Une valeur incluse dans la requête qui est également renvoyée dans la réponse de jeton. Il peut s’agir d’une chaîne de n’importe quel contenu que vous voulez utiliser. Généralement, une valeur unique générée de manière aléatoire est utilisée, de façon à empêcher les attaques par falsification de requête intersites. L’état est également utilisé pour coder les informations sur l’état de l’utilisateur dans l’application avant la demande d’authentification. Par exemple, la page ou la vue où était l’utilisateur. |
nonce | Obligatoire | Valeur incluse dans la demande, générée par l’application, qui est incluse dans le jeton d’ID résultant en tant que revendication. L’application peut ensuite vérifier cette valeur pour atténuer les attaques par relecture de jetons. La valeur est généralement une chaîne unique aléatoire qui identifie l’origine de la demande. |
prompt | Obligatoire | Pour actualiser et obtenir des jetons dans un IFrame masqué, utilisez prompt=none pour que l’IFrame ne se bloque pas sur la page de connexion et ne retourne pas immédiatement. |
login_hint | Obligatoire | Pour actualiser et obtenir des jetons dans un iframe masqué, incluez le nom d’utilisateur de l’utilisateur dans cet indice afin de faire la distinction entre différentes sessions que l’utilisateur pourrait avoir à un moment donné. Vous pouvez extraire le nom d’utilisateur à partir d’une précédente connexion à l’aide de la revendication preferred_username (l’étendue profile est nécessaire pour recevoir la revendication preferred_username ). |
domain_hint | Obligatoire | Peut être consumers ou organizations . Pour actualiser et obtenir des jetons dans un IFrame masqué, incluez la valeur domain_hint dans la demande. Extrayez la revendication tid du jeton d’ID d’une connexion précédente pour déterminer la valeur à utiliser (l’étendue profile est nécessaire pour recevoir la revendication tid ). Si la revendication tid est définie sur la valeur 9188040d-6c67-4c5b-b112-36a304b66dad , utilisez domain_hint=consumers . Sinon, utilisez domain_hint=organizations . |
Avec le paramètre prompt=none
, cette demande réussit ou échoue immédiatement, et retourne à votre application. Une réponse correcte est envoyée à votre application à l’URI de redirection, en utilisant la méthode spécifiée dans le paramètre response_mode
.
Réponse correcte
Une réponse de réussite utilisant response_mode=fragment
se présente ainsi :
GET https://aadb2cplayground.azurewebsites.net/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=arbitrary_data_you_sent_earlier
&token_type=Bearer
&expires_in=3599
&scope=https%3A%2F%2Fapi.contoso.com%2Ftasks.read
Paramètre | Description |
---|---|
access_token | Le jeton que l’application a demandé. |
token_type | Le type de jeton sera toujours Porteur. |
state | Si un paramètre state est inclus dans la demande, la même valeur doit apparaître dans la réponse. L’application doit vérifier que les valeurs state de la demande et de la réponse sont identiques. |
expires_in | Durée de validité du jeton d’accès (en secondes). |
scope | Les étendues de validité du jeton d’accès. |
Réponse d’erreur
Les réponses d’erreur peuvent également être envoyées à l’URI de redirection, pour que l’application puisse les traiter de façon appropriée. Pour prompt=none
, une erreur attendue se présente ainsi :
GET https://aadb2cplayground.azurewebsites.net/#
error=user_authentication_required
&error_description=the+request+could+not+be+completed+silently
Paramètre | Description |
---|---|
error | Une chaîne de code d’erreur qui peut être utilisée pour classer les types d’erreurs qui se produisent. Vous pouvez également utiliser la chaîne pour réagir aux erreurs. |
error_description | Un message d’erreur spécifique qui peut vous aider à identifier la cause principale d’une erreur d’authentification. |
Si vous recevez cette erreur dans la requête iFrame, l’utilisateur doit se connecter de nouveau de manière interactive, ceci pour récupérer un nouveau jeton.
Jetons d’actualisation
Les jetons d’ID et les jetons d’accès expirent après une courte période de temps. Votre application doit actualiser ces jetons périodiquement. Les flux implicites ne vous permettent pas d’obtenir un jeton d’actualisation pour des raisons de sécurité. Pour actualiser l’un ou l’autre type de jeton, utilisez le flux implicite dans un élément IFRAME HTML masqué. Dans la demande d’autorisation, incluez le paramètre prompt=none
. Pour recevoir une nouvelle valeur id_token, utilisez response_type=id_token
et scope=openid
, ainsi qu’un paramètre nonce
.
Envoi d’une demande de déconnexion
Lorsque vous souhaitez déconnecter l’utilisateur de l’application, redirigez l’utilisateur vers le point de terminaison Azure AD B2C pour effectuer cette déconnexion. Vous pouvez ensuite effacer la session de l’utilisateur dans l’application. Si vous ne le faites pas, l’utilisateur pourrait être en mesure de se réauthentifier à votre application sans avoir à saisir de nouveau ses informations d’identification, car il dispose d’une session d’authentification unique valide auprès d’Azure AD B2C.
Vous pouvez simplement rediriger l’utilisateur vers le end_session_endpoint
qui est répertorié dans le même document de métadonnées OpenID Connect décrit dans Validation du jeton d’ID. Par exemple :
GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
Paramètre | Obligatoire | Description |
---|---|---|
{tenant} | Oui | Nom de votre locataire Azure AD B2C. |
{policy} | Oui | Flux utilisateur que vous voulez utiliser pour déconnecter l’utilisateur de votre application. Il doit s’agir du même utilisateur que celui utilisé par l’application pour la connexion de l’utilisateur. |
post_logout_redirect_uri | Non | URL vers laquelle l’utilisateur doit être redirigé après la déconnexion. Si elle n’est pas incluse, Azure AD B2C affiche un message générique à l’utilisateur. |
state | Non | Si un paramètre state est inclus dans la demande, la même valeur doit apparaître dans la réponse. L’application doit vérifier que les valeurs state de la demande et de la réponse sont identiques. |
Notes
La redirection de l’utilisateur vers le end_session_endpoint
efface certains états de l’authentification unique de l’utilisateur auprès d’Azure AD B2C. Il ne déconnecte cependant pas l’utilisateur de la session du fournisseur d’identité sociale de l’utilisateur. Si l’utilisateur sélectionne le même fournisseur d’identité lors d’une connexion ultérieure, il sera réauthentifié sans avoir à entrer ses informations d’identification. Si un utilisateur veut se déconnecter de votre application Azure AD B2C, cela ne signifie pas nécessairement qu’il veut se déconnecter complètement, par exemple de son compte Facebook. Cependant, pour des comptes locaux, la session de l’utilisateur sera terminée correctement.
Étapes suivantes
Consultez l’exemple de code : Se connecter avec Azure AD B2C dans une SPA JavaScript.