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

# Mise en œuvre de l’API Node.js  (SPA + API)

> L’implémentation Node.js de l’API 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>;
};

Ce document fait partie du scénario d’architecture SPA + API et explique comment mettre en œuvre l’API dans Node.js. Veuillez vous référer au scénario pour obtenir des informations sur la solution implémentation.

Le code source complet de la mise en œuvre 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).

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

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

### Créer un fichier package.json

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

Laissez les paramètres par défaut ou modifiez-les selon votre convenance.

Le `package.json`  de notre exemple ressemble à ce qui suit :

```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"
}
```

### Installer les dépendances

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

* **express** : ce module ajoute le [cadre d’applications Web Express](https://expressjs.com/).
* **cors** : Le présent module ajoute la prise en charge de l’activation du [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), ce qui est nécessaire car l’API sera appelée à partir d’une application à page unique qui s’exécute sur un domaine différent dans un navigateur Web.
* **jwks-rsa** : cette bibliothèque récupère les clés de connexion RSA à partir d’un point de terminaison JWKS (JSON Web Key Set). À l’aide de `expressJwtSecret` nous pouvons générer un fournisseur de secret qui fournit la bonne clé de connexion à `express-jwt` en fonction du `kid` dans l’en-tête <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>. Pour en apprendre davantage, consultez [node-jwks-rsa GitHub repository](https://github.com/auth0/node-jwks-rsa).
* **express-jwt** : Ce module vous laisse authentifier les requêtes HTTP à l’aide de jetons JWT dans vos applications Node.js. Express-jwtusieurs fonctions qui facilitent le travail avec les JWT. Pour plus d’information consultez [express-jwt GitHub repository](https://github.com/auth0/express-jwt).
* **body-parser** : il s’agit d’un logiciel médiateur d’analyse de corps Node.js. Il extrait la partie entière du corps d’une requête entrante et l’expose sur `req.body` comme quelque chose de plus facile à interfacer. Pour plus d’informations et plusieurs alternatives, consultez le dépôt GitHub body-parser.

Pour installer ces dépendances, suivez les étapes suivantes :

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

### Implémenter les points de terminaison

Ouvrez votre répertoire API et créez un fichier  `server.js` . Votre code doit :

* Obtenir les dépendances.
* Implémenter le ou les points de terminaison.
* Lancer le serveur API.

Voici notre 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');

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

// Enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

// Create timesheets API endpoint
app.post('/timesheets', function(req, res){
  res.status(201).send({message: "This is the POST /timesheets endpoint"});
})

// Launch the API Server at localhost:8080
app.listen(8080);
```

Lancez votre serveur API en utilisant  `node server` et envoyez une requête HTTP POST à `localhost:8080/timesheets`. Vous verrez une réponse JSON avec le message `This is the POST /timesheets endpoint`.

Nous avons désormais notre point de terminaison, mais tout le monde peut l’appeler. Rendez-vous au paragraphe suivant pour voir comment nous pouvons résoudre ce problème.

## 2. Sécuriser les points de terminaison de l’API

Dans l’optique de valider notre jeton, nous utiliserons la fonction `jwt` fournie par le logiciel médiateur [express-jwt](https://github.com/auth0/express-jwt#usage), et `jwks-rsa` pour récupérer notre secret. Les bibliothèques remplissent les rôles suivants :

1. `express-jwt` décode le jeton et achemine la demande l’en-tête et les données utiles vers `jwksRsa.expressJwtSecret`.
2. `jwks-rsa` télécharge toutes les clés de connexion à partir du point de terminaison JWKS et vérifie si l’une des clés de connexion correspond à la valeur `kid` dans l’en-tête du jeton JWT. Si aucune des clés de connexion ne correspond à la valeur `kid`reçue, une erreur sera générée. Si nous avons une correspondance, nous transmettrons la bonne clé de connexion à `express-jwt`.
3. `express-jwt` poursuivra sa propre logique pour valider la signature du jeton, l’expiration, l'`audience` et l’`issuer`.

Les étapes que nous suivrons dans notre code sont :

* Créer la fonctionnalité logiciel médiateur pour valider le jeton d’accès.
* Activez l’utilisation du logiciel médiateur dans nos chemins.

Vous pouvez également écrire du code pour véritablement enregistrer la feuille de temps dans une base de données. Voici notre exemple d’implémentation (certains codes sont omis aux fins de concision) :

export const codeExample = `// set dependencies - code omitted

// Enable CORS - code omitted

// Create middleware for checking the JWT
const checkJwt = jwt({
  // Dynamically provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: \`https://{yourDomain}/.well-known/jwks.json\`
  }),

  // Validate the audience and the issuer
  audience: '{YOUR_API_IDENTIFIER}', //replace with your API's audience, available at Dashboard > APIs
  issuer: 'https://{yourDomain}/',
  algorithms: [ 'RS256' ]
});

// Enable the use of request body parsing middleware - code omitted

// create timesheets API endpoint - code omitted
app.post('/timesheets', checkJwt, function(req, res){
  var timesheet = req.body;

  // Save the timesheet to the database...

  //send the response
  res.status(201).send(timesheet);
});
// launch the API Server at localhost:8080 - code omitted`;

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

Si nous lançons notre serveur maintenant et effectuons un HTTP POST vers`localhost:8080/timesheets` nous obtiendrons le message d’erreur`Missing or invalid token`, ce qui est correct, car nous n’avons pas envoyé de jeton d’accès dans notre demande).

Pour tester également le scénario de fonctionnement, nous devons :

* Obtenir un jeton d’accès Pour plus d’informations sur la procédure à suivre pour y parvenir, reportez-vous à : [Get an Access Token](/docs/fr-ca/architecture-scenarios/application/server-api#get-an-access-token) (Obtenir un jeton d’accès).
* Invoquez l’API en ajoutant un en-tête `Authorization (Autorisation)` à notre requête avec la valeur `Bearer ACCESS_TOKEN (Porteur de jeton d’accès)`, où `ACCESS_TOKEN (jeton d’accès)` est la valeur du jeton que nous avons récupéré à la première étape.

## 3. Vérifiez les permissions de l’application

Á cette étape nous ajouterons à notre mise en œuvre la possibilité de vérifier si l’application a des autorisations (ou des `permissions`) pour utiliser notre point de terminaison afin de créer une feuille de temps. En particulier, nous voulons nous rassurer que le jeton a la bonne permission, qui est `batch:upload`.

Pour y parvenir, nous utilisons le paquet `express-jwt-authz` Node.js, donc ajoutez-le à votre projet :

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

Maintenant, ajoutez un appel à `jwtAuthz(...)` à votre logiciel médiateur pour vous assurer que le jeton JWT contient une permission particulière afin d’exécuter un point de terminaison particulier.

Nous ajouterons une dépendance supplémentaire. La bibliothèque **express-jwt-authz** , utilisée conjointement avec express-jwt, valide le jeton [JWT](https://auth0.com/docs/tokens/concepts/jwts) et s’assure qu’il possède les autorisations adéquates pour appeler le point de terminaison souhaité. Pour plus d’informations, consultez le [référentiel express-jwt-authz GitHub](https://github.com/auth0/express-jwt-authz).

Voici notre exemple d’implémentation (certains codes sont omis aux fins de concision) :

```javascript lines theme={null}
// set dependencies - some code omitted
const jwtAuthz = require('express-jwt-authz');

// Enable CORS - code omitted

// Create middleware for checking the JWT - code omitted

// Enable the use of request body parsing middleware - code omitted

// create timesheets API endpoint
app.post('/timesheets', checkJwt, jwtAuthz(['create:timesheets'], { customUserKey: 'auth' }), function(req, res){
  var timesheet = req.body;

  // Save the timesheet to the database...

  //send the response
  res.status(201).send(timesheet);
})

// launch the API Server at localhost:8080 - code omitted
```

Si nous invoquons notre API avec un jeton qui n’inclut pas cette permission, nous devrions obtenir le message d’erreur Interdit avec le code d’état HTTP `403`. Vous pouvez l’essayer en supprimant cette permission de votre API.

## 4. Déterminer l’identité de l’utilisateur

Le logiciel médiateur `express-jwt` utilisé pour valider le jeton JWT configure également `req.auth` avec les informations contenues dans le jeton JWT. Si vous voulez utiliser la demande `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, nous souhaitons cependant utiliser l’adresse courriel de l’utilisateur comme identifiant unique.

La première chose que nous devons faire est d’écrire une règle qui ajoutera l’adresse courriel de l’utilisateur au jeton d’accès. Accédez à la [section Règles](https://manage.auth0.com/#/rules%7D) du Dashboard, puis cliquez sur le bouton**Créer une règle**.

Vous pouvez donner à la règle un nom descriptif, par exemple `Ajouter courriel au jeton d’accès`, puis utiliser le code suivant pour la règle :

```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` est utilisé pour s’assurer que la requête possède un nom unique et n’entre pas en conflit avec les noms de requêtes OIDC standard. Cependant, Auth0 prend en charge les demandes personnalisées avec et sans espace de noms. Pour plus d’informations sur les demandes personnalisées, consultez [Créer des demandes personnalisées](/docs/fr-ca/secure/tokens/json-web-tokens/create-custom-claims).

Ensuite, dans votre API, vous pouvez récupérer la valeur de la demande à partir de `req.auth`, et l’utiliser en tant qu’identité unique de l’utilisateur que vous pouvez associer aux entrées de feuilles de temps.

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

  // Associate the timesheet entry with the current user
  var userId = req.auth['https://api.exampleco.com/email'];
  timesheet.user_id = userId;

  // Save the timesheet to the database...

  //send the response
  res.status(201).send(timesheet);
});
```
