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

> L’implémentation Node.js de l’API pour le scénario d’architecture SPAs + API

# Implémentation de l’API Node.js (SPAs + 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>;
};

<div id="nodejs-api-implementation-spas-api">
  # Implémentation de l’API Node.js (SPAs + API)
</div>

Ce document fait partie du scénario d’architecture SPA + API et explique comment implémenter l’API en Node.js. Consultez le scénario pour en savoir plus sur la solution implémentée.

Le code source complet de l’implémentation de l’API Node.js se trouve dans [ce dépôt GitHub](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-api/node).

<div id="step-1-define-the-api-endpoints">
  ## Étape 1. Définir les points de terminaison de l’API
</div>

Nous utiliserons le [framework d’applications Web Express](http://expressjs.com/) pour construire notre API Node.js.

<div id="create-a-packagejson-file">
  ### Créer un fichier package.json
</div>

Créez un dossier pour votre API, placez-vous-y et exécutez `npm init`. Cette commande configurera votre fichier `package.json`.

Vous pouvez conserver les paramètres par défaut ou les modifier selon vos besoins.

Le `package.json` de notre exemple ressemble à ceci :

```json lines theme={null}
{
  "name": "timesheets-api",
  "version": "1.0.0",
  "description": "API used to add timesheet entries for employees and contractors",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/auth0-samples/auth0-pnp-timesheets.git"
  },
  "author": "Auth0",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/auth0-samples/auth0-pnp-timesheets/issues"
  },
  "homepage": "https://github.com/auth0-samples/auth0-pnp-timesheets#readme"
}
```

<div id="install-the-dependencies">
  ### Installer les dépendances
</div>

Ensuite, nous devons configurer nos dépendances. Nous utiliserons les modules suivants :

* **express** : Ce module ajoute le [framework d’applications Web Express](https://expressjs.com/).
* **cors** : Ce module ajoute la prise en charge de l’activation de [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), ce qui est nécessaire puisque l’API sera appelée à partir d’une application monopage exécutée sur un domaine différent dans un navigateur Web.
* **jwks-rsa** : Cette bibliothèque récupère des clés de signature RSA à partir d’un endpoint JWKS (ensemble de clés JSON Web). En utilisant `expressJwtSecret`, nous pouvons générer un fournisseur de secrets qui fournira la bonne clé de signature à `express-jwt` en fonction du `kid` dans l’en-tête du <Tooltip tip="JSON Web Token (JWT) : format standard de ID Token (et souvent format de Jeton d’accès) utilisé pour représenter des revendications de façon sécurisée entre deux parties." cta="Voir le glossaire" href="/fr-CA/docs/glossary?term=JWT">JWT</Tooltip>. Pour en savoir plus, consultez le [dépôt GitHub node-jwks-rsa](https://github.com/auth0/node-jwks-rsa).
* **express-jwt** : Ce module vous permet d’authentifier des requêtes HTTP à l’aide de jetons JWT dans vos applications Node.js. Il fournit plusieurs fonctions qui facilitent l’utilisation des JWT. Pour en savoir plus, consultez le [dépôt GitHub express-jwt](https://github.com/auth0/express-jwt).
* **body-parser** : Il s’agit d’un middleware d’analyse du corps des requêtes pour Node.js. Il extrait l’intégralité du corps d’un flux de requête entrant et l’expose dans `req.body` sous une forme plus facile à utiliser. Pour en savoir plus et découvrir plusieurs solutions de rechange, consultez le dépôt GitHub de body-parser.

Pour installer ces dépendances, exécutez la commande suivante :

```bash wrap lines theme={null}
npm install express cors express-jwt jwks-rsa body-parser express-jwt-authz --save
```

<div id="implement-the-endpoints">
  ### Implémentez les points de terminaison
</div>

Accédez au répertoire de votre API et créez un fichier `server.js`. Votre code doit :

* Installer les dépendances.
* Implémenter le ou les points de terminaison.
* Démarrer le serveur d’API.

Voici un exemple d’implémentation :

```javascript lines theme={null}
const express = require('express');
const app = express();
const { expressjwt: jwt } = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const cors = require('cors');
const bodyParser = require('body-parser');

// Activer CORS
app.use(cors());

// Activer l'utilisation du middleware d'analyse du corps de la requête
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

// Créer l'endpoint de l'API des feuilles de temps
app.post('/timesheets', function(req, res){
  res.status(201).send({message: "This is the POST /timesheets endpoint"});
})

// Lancer le serveur d'API à localhost:8080
app.listen(8080);
```

Lancez votre serveur d’API à l’aide de `node server` et envoyez une requête HTTP POST à `localhost:8080/timesheets`. Vous devriez voir une réponse JSON contenant le message `This is the POST /timesheets endpoint`.

Nous avons maintenant notre point de terminaison, mais n’importe qui peut l’appeler. Passez au paragraphe suivant pour voir comment régler ce problème.

<div id="step-2-secure-the-api-endpoints">
  ## Étape 2. Sécuriser les points de terminaison de l’API
</div>

Pour valider notre jeton, nous utiliserons la fonction `jwt`, fournie par le [middleware express-jwt](https://github.com/auth0/express-jwt#usage), ainsi que `jwks-rsa` pour récupérer notre secret. Les bibliothèques font ce qui suit :

1. `express-jwt` décodera le jeton et transmettra la requête, l’en-tête et le payload à `jwksRsa.expressJwtSecret`.
2. `jwks-rsa` téléchargera ensuite toutes les clés de signature depuis le point de terminaison JWKS et vérifiera si l’une d’elles correspond au `kid` dans l’en-tête du JWT. Si aucune clé de signature ne correspond au `kid` reçu, une erreur sera générée. S’il y a correspondance, nous transmettrons la bonne clé de signature à `express-jwt`.
3. `express-jwt` poursuivra ensuite sa propre logique pour valider la signature du jeton, l’expiration, `audience` et l’émetteur.

Les étapes que nous suivrons dans notre code sont les suivantes :

* Créer la fonction middleware pour valider le <Tooltip tip="Jeton d’accès : justificatif d’autorisation, sous la forme d’une chaîne opaque ou d’un JWT, utilisé pour accéder à une API." cta="Consulter le glossaire" href="/fr-CA/docs/glossary?term=Access+Token">Jeton d’accès</Tooltip>.
* Activer l’utilisation du middleware dans nos routes.

Vous pouvez également écrire du code pour enregistrer réellement la feuille de temps dans une base de données. Voici notre implémentation d’exemple (une partie du code est omise par souci de concision) :

export const codeExample = `// définir les dépendances - code omis

// Activer CORS - code omis

// Créer le middleware pour vérifier le JWT
const checkJwt = jwt({
  // Fournit dynamiquement une clé de signature en fonction du kid dans l’en-tête et des clés de signature fournies par le endpoint JWKS
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: \`https://{yourDomain}/.well-known/jwks.json\`
  }),

  // Valider l’audience et l’émetteur
  audience: '{YOUR_API_IDENTIFIER}', // remplacez par l’audience de votre API, accessible dans Auth0 Dashboard > APIs
  issuer: 'https://{yourDomain}/',
  algorithms: [ 'RS256' ]
});

// Activer le middleware d’analyse du corps de la requête - code omis

// créer le endpoint API des feuilles de temps - code omis
app.post('/timesheets', checkJwt, function(req, res){
  var timesheet = req.body;

  // Enregistrer la feuille de temps dans la base de données...

  // envoyer la réponse
  res.status(201).send(timesheet);
});
// lancer le serveur d’API sur localhost:8080 - code omis`;

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

Si nous démarrons notre serveur maintenant et envoyons une requête HTTP POST à `localhost:8080/timesheets`, nous devrions obtenir le message d’erreur `Missing or invalid token` (ce qui est tout à fait normal, puisque nous n’avons pas envoyé de jeton d’accès dans notre requête).

Pour tester aussi le cas où tout fonctionne, nous devons :

* Obtenir un Jeton d’accès. Pour savoir comment faire, consultez : [Obtenir un Jeton d’accès](/fr-CA/docs/get-started/architecture-scenarios/server-application-api#get-an-access-token).
* Appeler l’API en ajoutant à notre requête un en-tête `Authorization` avec la valeur `Bearer ACCESS_TOKEN` (où `ACCESS_TOKEN` est la valeur du jeton récupéré à la première étape).

<div id="step-3-check-the-application-permissions">
  ## Étape 3. Vérifier les autorisations de l’application
</div>

À cette étape, nous allons ajouter à notre implémentation la possibilité de vérifier si l’application dispose des autorisations (ou du `scope`) nécessaires pour utiliser notre point de terminaison et créer une feuille de temps. Plus précisément, nous voulons nous assurer que le jeton contient le bon scope, soit `batch:upload`.

Pour ce faire, nous utiliserons le package Node.js `express-jwt-authz`. Ajoutez-le donc à votre projet :

```bash lines theme={null}
npm install express-jwt-authz --save
```

Il suffit maintenant d’ajouter un appel à `jwtAuthz(...)` à votre middleware pour vous assurer que le JWT contient le scope requis afin d’exécuter un point de terminaison donné.

Nous allons ajouter une dépendance supplémentaire. La bibliothèque **express-jwt-authz**, utilisée conjointement avec express-jwt, valide le [JWT](/fr-CA/docs/secure/tokens/json-web-tokens) et s’assure qu’il comporte les autorisations appropriées pour appeler le point de terminaison souhaité. Pour en savoir plus, consultez le [dépôt GitHub d’express-jwt-authz](https://github.com/auth0/express-jwt-authz).

Voici notre implémentation d’exemple (une partie du code est omise par souci de concision) :

```javascript lines theme={null}
// définir les dépendances - une partie du code est omise
const jwtAuthz = require('express-jwt-authz');

// Activer CORS - code omis

// Créer le middleware pour vérifier le JWT - code omis

// Activer l'utilisation du middleware d'analyse du corps de la requête - code omis

// créer le endpoint de l'API des feuilles de temps
app.post('/timesheets', checkJwt, jwtAuthz(['create:timesheets'], { customUserKey: 'auth' }), function(req, res){
  var timesheet = req.body;

  // Enregistrer la feuille de temps dans la base de données...

  //envoyer la réponse
  res.status(201).send(timesheet);
})

// lancer le serveur d'API à localhost:8080 - code omis
```

Si nous appelons notre API avec un jeton qui n’inclut pas ce scope, nous devrions obtenir le message d’erreur Forbidden avec le code d’état HTTP `403`. Vous pouvez le tester en supprimant ce scope de votre API.

<div id="step-4-determine-the-user-identity">
  ## Étape 4. Déterminer l’identité de l’utilisateur
</div>

Le middleware `express-jwt` utilisé pour valider le JWT définit également `req.auth` avec les informations contenues dans le JWT. Si vous voulez utiliser la revendication `sub` pour identifier l’utilisateur de manière unique, vous pouvez simplement utiliser `req.auth.sub`.

Dans le cas de l’application de feuilles de temps, cependant, nous voulons utiliser l’adresse de courriel de l’utilisateur comme identifiant unique.

La première chose à faire est d’écrire une Rule qui ajoutera l’adresse de courriel de l’utilisateur au Jeton d’accès. Accédez à la [section Rules](https://manage.auth0.com/#/rules%7D) de l’Auth0 Dashboard, puis cliquez sur le bouton **Create Rule**.

Vous pouvez donner à la Rule un nom descriptif, par exemple `Add email to Access Token`, puis utiliser le code suivant pour la Rule :

```javascript lines theme={null}
function (user, context, callback) {
  const namespace = 'https://api.exampleco.com/';
  context.accessToken[namespace + 'email'] = user.email;
  callback(null, user, context);
}
```

Le `namespace` sert à garantir que la revendication a un nom unique et qu’elle n’entre pas en conflit avec les noms des revendications OIDC standard. Cependant, Auth0 prend en charge les revendications personnalisées avec ou sans espace de noms. Pour en savoir plus sur les revendications personnalisées, consultez [Create Custom Claims](/fr-CA/docs/secure/tokens/json-web-tokens/create-custom-claims).

Ensuite, dans votre API, vous pouvez récupérer la valeur de la revendication depuis `req.auth` et l’utiliser comme identifiant utilisateur unique que vous pouvez associer aux entrées de feuille de temps.

```js lines theme={null}
app.get('/timesheets', checkJwt, jwtAuthz(['read:timesheets'], { customUserKey: 'auth' }), function(req, res) {
  var timesheet = req.body;

  // Associer l'entrée de feuille de temps à l'utilisateur actuel
  var userId = req.auth['https://api.exampleco.com/email'];
  timesheet.user_id = userId;

  // Enregistrer la feuille de temps dans la base de données...

  //envoyer la réponse
  res.status(201).send(timesheet);
});
```
