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.

Swimlane-style diagram showing the OpenID Connect implicit flow

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 exemple b2c_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 à Azure AD 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 de id_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ètre state 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 et exp 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 Azure AD Multi-Factor Authentication.

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 Azure AD. 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.