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

# Configuration de l’API et de la SPA (SPA + API)

> Configuration de l’API et de la SPA pour le scénario d’architecture SPA + API

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

Dans cette section, nous verrons comment nous pouvons mettre en œuvre une API pour notre scénario.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Pour des raisons de simplicité, notre implémentation se concentrera uniquement sur l’authentification et l’autorisation. Comme vous le verrez dans les exemples, l’entrée de la feuille de temps sera codée en dur et l’API ne conservera pas l’entrée de la feuille de temps. Au lieu de cela, elle renverra simplement certaines informations.
</Callout>

## Définir les points de terminaison de l’API

Nous devons d’abord définir les points de terminaison de notre API.

<Card title="Qu’est-ce qu’un point de terminaison d’API?">
  Un **point de terminaison d’API**

  Par exemple, une API de restaurant pourrait avoir des points de terminaison tels que `/orders` et `/customers`. Une application qui se connecte à cette API peut effectuer des opérations CRUD (create, read, update, delete) en appelant un point de terminaison d’API à l’aide de la méthode HTTP associée (`POST`, `GET`, `PUT`, `PATCH` ou `DELETE`).
</Card>

Pour cette implémentation, nous ne définirons que 2 points de terminaison : un pour récupérer une liste de toutes les feuilles de temps d’un employé, et un autre pour permettre à un employé de créer une nouvelle entrée de feuille de temps.

Une requête `HTTP GET` au point de terminaison `/timesheets` permettra à un utilisateur de récupérer ses feuilles de temps, et une requête `HTTP POST` au point de terminaison `/timesheets` permettra à un utilisateur d’ajouter une nouvelle feuille de temps.

**Voir l’implémentation dans**[**Node.js**](https://auth0.com/docs/architecture-scenarios/application/spa-api/api-implementation-nodejs#1-define-the-api-endpoints).

### Sécuriser les points de terminaison

Lorsqu’une API reçoit une requête avec un jeton d’accès du porteur dans l’en-tête, la première chose à faire est de valider le jeton. Cette validation consiste en une série d’étapes, et si l’une de ces étapes échoue, la requête doit être rejetée avec un message d’erreur `Missing or invalid token` envoyé à l’application appelante.

Les validations que l’API doit effectuer sont les suivantes :

* Vérifier que le jeton <Tooltip href="/docs/fr-ca/glossary?term=json-web-token" tip="Jeton Web JSON (JWT)
  Format standard de jeton d’ID (et souvent de jeton d’accès) utilisé pour représenter en toute sécurité des demandes entre deux parties." cta="Voir le glossaire">JWT</Tooltip> est bien formé
* Vérifier la signature
* Valider les demandes standard

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  [JWT.io](https://jwt.io/) fournit une liste de bibliothèques qui peuvent faire la plupart du travail pour vous : analyser le JWT, vérifier la signature et les demandes.
</Callout>

Une partie du processus de validation consiste également à vérifier les permissions de l’application (scopes), mais nous aborderons cette question séparément dans le prochain paragraphe de ce document.

Pour en savoir plus sur la validation des jetons d’accès, consultez [Valider les jetons d’accès](https://auth0.com/docs/tokens/guides/validate-access-tokens).

**Voir l’implémentation dans**[**Node.js**](https://auth0.com/docs/architecture-scenarios/application/spa-api/api-implementation-nodejs#2-secure-the-api-endpoints).

### Vérifier les permissions de l’application

Nous avons maintenant vérifié que le jeton JWT est valide. La dernière étape consiste à vérifier que l’application dispose des permissions requises pour accéder aux ressources protégées.

Pour ce faire, l’API doit vérifier les permissions du jeton JWT décodé en consultant l’objet [permissions](https://auth0.com/docs/scopes). Cette demande fait partie de la charge utile et il s’agit d’une liste de chaînes séparées par des espaces.

**Voir l’implémentation dans**[**Node.js**](https://auth0.com/docs/architecture-scenarios/application/spa-api/api-implementation-nodejs#3-check-the-client-permissions).

### Déterminer l’identité utilisateur

Pour les deux points de terminaison (récupération de la liste des feuilles de temps et ajout d’une nouvelle feuille de temps), nous devrons déterminer l’identité utilisateur.

Pour récupérer la liste des feuilles de temps, cela permet de s’assurer que nous renvoyons uniquement les feuilles de temps appartenant à l’utilisateur qui fait la demande, et pour ajouter une nouvelle feuille de temps, cela permet de s’assurer que la feuille de temps est associée à l’utilisateur qui fait la demande.

L’une des demandes standard de JWT est la demande `sub` qui détermine le demandeur qui fait l’objet de la demande. Dans le cas du flux d’autorisation implicite, cette demande contiendra l’identité utilisateur, qui sera l’identifiant unique de l’utilisateur Auth0. Vous pouvez l’utiliser pour associer n’importe quelle information dans des systèmes externes à un utilisateur particulier.

Vous pouvez également utiliser une demande personnalisée pour ajouter au jeton d’accès un autre attribut de l’utilisateur, tel que son adresse courriel, et l’utiliser pour identifier l’utilisateur de manière unique.

**Voir l’implémentation dans**[**Node.js**](https://auth0.com/docs/architecture-scenarios/application/spa-api/api-implementation-nodejs#4-determine-the-user-identity).

## Mettre en œuvre la SPA

Dans cette section, nous verrons comment mettre en œuvre une SPA pour notre scénario.

### Autoriser l’utilisateur

Pour autoriser l’utilisateur, nous utiliserons la [bibliothèque auth0.js](https://auth0.com/docs/libraries/auth0js). Vous pouvez initialiser une nouvelle instance de l’application Auth0 comme suit :

export const codeExample = `var auth0 = new auth0.WebAuth({
  clientID: '{yourClientId}',
  domain: '{yourDomain}',
  responseType: 'token id_token',
  audience: 'YOUR_API_IDENTIFIER',
  redirectUri: '{https://yourApp/callback}',
  scope: 'openid profile read:timesheets create:timesheets'
});`;

<AuthCodeBlock children={codeExample} language="javascript" />

Vous devez transmettre les valeurs de configuration suivantes :

* **clientID** : La valeur de votre ID client Auth0. Vous pouvez la récupérer à partir des Paramètres de votre application dans le [Dashboard](https://manage.auth0.com/#/applications%7D).
* **Domaine**  : La valeur de votre domaine Auth0. Vous pouvez la récupérer à partir des Paramètres de votre application dans le [Dashboard](https://manage.auth0.com/#/applications%7D).
* **responseType** : Indique le flux d’authentification à utiliser. Pour une SPA qui utilise le **Flux implicite**, cette valeur doit être définie sur `token ID_token`. La partie `token` déclenche le renvoi par le flux d’un jeton d’accès dans le fragment URL, tandis que la partie `id_token` déclenche également le renvoi par le flux d’un jeton d’ID.
* **<Tooltip data-tooltip-id="react-containers-DefinitionTooltip-1" tip="">audience</Tooltip>** : Valeur de l’identifiant de votre API. Vous pouvez la récupérer à partir des [Paramètres de votre API](https://manage.auth0.com/#/apis%7D) dans le Tableau de bord.
* **redirectUri** : L’URL vers laquelle Auth0 doit rediriger l’utilisateur une fois celui-ci authentifié.
* **scope** : Les [permissions](https://auth0.com/docs/scopes) qui déterminent les informations à renvoyer dans le jeton d’ID et dans le jeton d’accès. Une permission du `openid profile` (profil <Tooltip href="/docs/fr-ca/glossary?term=openid" tip="OpenID
  Norme ouverte d’authentification qui permet aux applications de vérifier l’identité des utilisateurs sans avoir à collecter leurs informations de connexion." cta="Voir le glossaire">openid</Tooltip>) renvoie toutes les informations du profil utilisateur dans le jeton d’ID. Vous devez également demander les permissions requises pour appeler l’API, dans ce cas les permissions `read:timesheets create:timesheets`. Cela garantira que le jeton d’accès possède ces permissions.

Pour lancer le flux d’authentification, vous pouvez appeler la méthode `authorise()` :

```javascript lines theme={null}
auth0.authorize();
```

Après l’authentification, Auth0 redirigera l’utilisateur vers l’URL **redirectUri** que vous avez spécifiée lors de la configuration de la nouvelle instance de l’application Auth0. À ce stade, vous devrez appeler la méthode `parseHash()` qui analyse un fragment de hachage URL pour extraire le résultat d’une réponse d’authentification Auth0.

Le contenu de l’objet authResult renvoyé par la méthode parseHash dépend des paramètres d’authentification utilisés. Il peut comprendre les éléments suivants :

* **idToken** : Un jeton d’ID JWT contenant des informations de profil utilisateur
* **accessToken** : Un jeton d’accès pour l’API, spécifié par l’objet **audience**.
* **expiresIn** : Chaîne contenant le délai d’expiration (en secondes) du jeton d’accès.

Déterminez le meilleur emplacement où [stocker les jetons](https://auth0.com/docs/tokens/concepts/token-storage). Si votre application à page unique dispose d’un serveur dorsal, les jetons doivent être gérés côté serveur à l’aide du [flux de code d’autorisation](https://auth0.com/docs/flows/concepts/auth-code) ou du [Flux de code d’autorisation avec Proof Key for Code Exchange (PKCE)](https://auth0.com/docs/flows/concepts/auth-code-pkce).

Si vous avez une application à page unique (SPA) sans serveur dorsal correspondant, votre SPA devrait demander de nouveaux jetons au moment de la connexion et les stocker en mémoire sans aucune persistance. Pour effectuer des appels d’API, votre SPA utilisera alors la copie du jeton en mémoire.

Pour voir un exemple de gestion des sessions dans les SPA, consultez la section[Gérer les jetons d’authentification](https://auth0.com/docs/quickstart/spa/vanillajs#handle-authentication-tokens) du [JavaScriptGuide de démarrage rapide d’une application à page unique](https://auth0.com/docs/quickstart/spa/vanillajs).

**Voir la mise en œuvre dans**[**Angular 2**](https://auth0.com/docs/architecture-scenarios/application/spa-api/spa-implementation-angular2#2-authorize-the-user).

### Obtenez le profil utilisateur

<Card title="Extraire des informations du jeton">
  Cette section démontre comment récupérer les informations de l’utilisateur en utilisant le jeton d’accès et le point de terminaison [/userinfo](https://auth0.com/docs/api/authentication#get-user-info). Pour éviter cet appel d’API, vous pouvez simplement décoder le jeton d’ID  [en utilisant une bibliothèque](https://jwt.io/#libraries-io) (assurez-vous de la valider d’abord). Si vous avez besoin de davantage d’informations utilisateur, envisagez d’utiliser  [notre Management API](https://auth0.com/docs/api/management/v2#!/Users/get_users_by_id) à partir de votre système dorsal.
</Card>

La méthode `client.userInfo` peut être appelée en transmettant le jeton `authResult.accessToken` retourné afin de récupérer les informations du profil de l’utilisateur. Elle fera une requête au point de terminaison [/userinfo](https://auth0.com/docs/api/authentication#get-user-info) et retournera l’objet `user`, qui contient les informations de l’utilisateur, comme dans l’exemple ci-dessous :

```json lines theme={null}
{
    "email_verified": "false",
    "email": "test@example.com",
    "clientID": "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH",
    "updated_at": "2017-02-07T20:50:33.563Z",
    "name": "tester9@example.com",
    "picture": "https://gravatar.com/avatar/example.png",
    "user_id": "auth0|123456789012345678901234",
    "nickname": "tester9",
    "created_at": "2017-01-20T20:06:05.008Z",
    "sub": "auth0|123456789012345678901234"
}
```

Vous pouvez accéder à l’une de ces propriétés dans la fonction de rappel passée lors de l’appel de la fonction `userInfo` :

```javascript lines theme={null}
const accessToken = authResult.accessToken;

auth0.client.userInfo(accessToken, (err, profile) => {
  if (profile) {
    // Get the user’s nickname and profile image
    var nickname = profile.nickname;
    var picture = profile.picture;
  }
});
```

**Voir la mise en œuvre dans**[**Angular 2**](https://auth0.com/docs/architecture-scenarios/application/spa-api/spa-implementation-angular2#3-get-the-user-profile).

### Afficher les éléments de l’interface utilisateur de manière conditionnelle en fonction de la permission

Selon la permission de l’utilisateur visible dans l’objet `scope`, vous pouvez afficher ou masquer certains éléments de l’interface utilisateur. Pour déterminer la permission accordée à un utilisateur, vous devez stocker la permission initialement demandée lors du processus d’autorisation. Lorsqu’un utilisateur est autorisé, la permission `scope` sera également renvoyée dans l’objet `authResult`.

Si la valeur `scope` dans l’objet `authResult` est vide, alors toutes les permissions qui ont été demandées ont été accordées. Si la valeur `scope` de l’objet `authResult` n’est pas vide, cela signifie qu’un ensemble différent de permissions a été accordé, et vous devez utiliser celles de l’objet `authResult.scope`.

**Voir la mise en œuvre dans**[**Angular 2**](https://auth0.com/docs/architecture-scenarios/application/spa-api/spa-implementation-angular2#4-display-ui-elements-conditionally-based-on-scope).

### Appeler l’API

Pour accéder aux ressources sécurisées à partir de votre API, le jeton d’accès de l’utilisateur authentifié doit être inclus dans les demandes qui lui sont envoyées. Pour ce faire, il faut envoyer le jeton d’accès dans un en-tête `Authorization` à l’aide du schéma `Bearer`.

**Voir la mise en œuvre dans**[**Angular 2**](https://auth0.com/docs/architecture-scenarios/application/spa-api/spa-implementation-angular2#5-call-the-api).

### Renouveler le jeton d’accès

Par mesure de sécurité, il est recommandé de limiter la durée de vie du jeton d’accès d’un utilisateur. Lorsque vous créez une API dans le <Tooltip href="/docs/fr-ca/glossary?term=auth0-dashboard" tip="Auth0 Dashboard
Principal produit d’Auth0 pour configurer vos services." cta="Voir le glossaire">Auth0 Dashboard</Tooltip>, la durée de vie par défaut est de `7200` secondes (2 heures), mais elle peut être contrôlée par API.

Une fois un jeton d’accès expiré, il ne peut plus être utilisé pour accéder à une API. Pour obtenir à nouveau l’accès, un nouveau jeton d’accès doit être obtenu.

L’obtention d’un nouveau jeton d’accès peut être effectuée en répétant le flux d’authentification utilisé pour obtenir le jeton d’accès initial. Dans une SPA, ce n’est pas idéal, car vous ne souhaitez pas nécessairement rediriger l’utilisateur à l’écart de sa tâche actuelle pour refaire le flux d’authentification.

Dans des cas comme celui-ci, vous pouvez utiliser l’[authentification silencieuse](https://auth0.com/docs/api-auth/tutorials/silent-authentication). L’authentification silencieuse vous permet ainsi d’effectuer un flux d’authentification où Auth0 répondra uniquement par des redirections, et jamais par une page de connexion. Pour que cette authentification fonctionne, elle nécessite toutefois que l’utilisateur ait déjà été connecté par [Authentification unique (SSO)](https://auth0.com/docs/sso).

**Voir la mise en œuvre dans**[**Angular 2**](https://auth0.com/docs/architecture-scenarios/application/spa-api/spa-implementation-angular2#6-renew-the-access-token).
