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

> The Node.js implementation of the API for the Mobile + API architecture scenario

# Node.js API Implementation (Mobile Apps + API)

This document is part of the Mobile + API Architecture Scenario and it explains how to implement the API in Node.js. The full source code for the Node.js API implementation can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-api/node).

Please refer to the scenario for information on the implemented solution.

<AccordionGroup>
  <Accordion title="1 Define the API endpoints">
    This implementation uses the [Express web application framework](http://expressjs.com/) to build a Node.js API.

    ##### Create a package.json File

    Create a folder for your API, navigate into it, and run `npm init`. This sets up your `package.json` file.

    Leave the default settings or change them as you see fit.

    Our sample's `package.json` looks like the following:

    ```json lines
    {
      "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"
    }
    ```

    ##### Install the Dependencies

    Next, set the dependencies with the following modules:

    * **express**: This module adds the [Express web application framework](https://expressjs.com/).
    * **cors**: This module adds support for enabling [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), which is required since the API is called from a Single-Page Application that runs on a different domain inside a web browser.
    * **jwks-rsa**: This library retrieves RSA signing keys from a JWKS (JSON Web Key Set) endpoint. Using `expressJwtSecret`, we can generate a secret provider that provides the right signing key to `express-jwt` based on the `kid` in the JWT header. To learn more, refer to the [node-jwks-rsa GitHub repository](https://github.com/auth0/node-jwks-rsa).
    * **express-jwt**: This module authenticates HTTP requests using JWT tokens in your Node.js applications. It provides several functions that make working with JWTs easier. For more information, refer to the [express-jwt GitHub repository](https://github.com/auth0/express-jwt).
    * **body-parser**: This is a Node.js body parsing middleware. It extracts the entire body portion of an incoming request stream and exposes it on `req.body` as something easier with which to interface.

    To install these dependencies run the following:

    ```bash wrap lines
    npm install express cors express-jwt jwks-rsa body-parser express-jwt-authz --save
    ```

    ##### Implement the Endpoints

    Navigate to your API directory and create a `server.js` file. Your code needs to:

    * Get the dependencies.
    * Implement the endpoint(s).
    * Launch the API server.

    This is our sample implementation:

    ```javascript lines
    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);
    ```

    Launch your API server using `node server` and make an HTTP POST request to `localhost:8080/timesheets`. You should see a JSON response with the message `This is the POST /timesheets endpoint`.

    So now we have our endpoint but anyone can call it. Continue to the next step to see how we can fix this.
  </Accordion>

  <Accordion title="2 Secure the API endpoints">
    In order to validate our token, use the `jwt` function, provided by the [express-jwt middleware](https://github.com/auth0/express-jwt#usage), and the `jwks-rsa` to retrieve our secret. The libraries do the following:

    1. `express-jwt` decodes the token and pass the request, the header, and the payload to `jwksRsa.expressJwtSecret`.
    2. `jwks-rsa` downloads all signing keys from the JWKS endpoint and see if a one of the signing keys matches the `kid` in the header of the JWT. If none of the signing keys match the incoming `kid`, an error will be thrown. If we have a match, pass the right signing key to `express-jwt`.
    3. `express-jwt` continues its own logic to validate the signature of the token, the expiration, `audience` and the `issuer`.

    The steps we will follow in our code are:

    * Create the middleware function to validate the access token.
    * Enable the use of the middleware in our routes.

    You can also write some code to actually save the timesheet to a database. This is our sample implementation (some code is omitted for brevity):

    ```javascript lines expandable
    // 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
    ```

    If we launch our server now and do an HTTP POST to `localhost:8080/timesheets` we should get the error message `Missing or invalid token` (which is accurate since we didn’t send an access token in our request).

    In order to test the working scenario as well we need to:

    * Get an access token. For details on how to do so refer to: [Get an Access Token](/docs/get-started/architecture-scenarios/server-application-api#get-an-access-token).
    * Invoke the API while adding an `Authorization` header to our request with the value `Bearer ACCESS_TOKEN` (where `ACCESS_TOKEN` is the value of the token we retrieved in the first step).
  </Accordion>

  <Accordion title="3 Check the app permissions">
    In this step, we add the ability to check if the application has permissions (or scopes) and use our endpoint in order to create a timesheet. In particular, we want to ensure that the token has the correct scope, which is `batch:upload`.

    In order to do this, we make use of the `express-jwt-authz` Node.js package, so add that to your project:

    ```bash lines
    npm install express-jwt-authz --save
    ```

    Now add a call to `jwtAuthz(...)` to your middleware to ensure that the JWT contain a particular scope in order to execute a particular endpoint.

    We add an additional dependency. The **express-jwt-authz** library, which is used in conjunction with express-jwt, validates the [JWT](/docs/secure/tokens/json-web-tokens) and ensures it bears the correct permissions to call the desired endpoint. For more information, refer to the [express-jwt-authz GitHub repository](https://github.com/auth0/express-jwt-authz).

    This is our sample implementation (some code is omitted for brevity):

    ```javascript lines
    // 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
    ```

    If we invoke our API with a token that does not include this scope, then we should get the error message Forbidden with the HTTP status code `403`. You can test this by removing this scope from your API.
  </Accordion>

  <Accordion title="4 Determine User Identity">
    The `express-jwt` middleware that is used to validate the JWT also sets `req.user` with the information contained in the JWT. If you want to use the `sub` claim to identify the user uniquely, you can use `req.user.sub`. For the timesheets application, we want to use the email address of the user as a unique identifier.

    ##### Create an Action

    First, [create a new Action](/docs/customize/actions/write-your-first-action) that will add the email address of the user to the access token.

    1. Navigate to [Auth0 Dashboard > Actions > Library](https://manage.auth0.com/#/actions/library), and select **Build Custom**.
    2. Enter a descriptive **Name** for your Action (for example, `Add email to access token`), select the **Login / Post Login** trigger, and select **Create**.
    3. Locate the Actions Code Editor, copy the following JavaScript code into it, and select **Save Draft** to save your changes:

       ```text lines
       exports.onExecutePostLogin = async (event, api) => {
         const namespace = 'https://my-app.example.com';
         api.accessToken.setCustomClaim(`${namespace}/email`, event.user.email);
       }
       ```

           <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
             The `namespace` is used to ensure the claim has a unique name that does not clash with standard OIDC claims or internal services. To learn more about restrictions and guidelines with namespaced and non-namespaced claims, read [Create Custom Claims](/docs/secure/tokens/json-web-tokens/create-custom-claims).
           </Callout>
    4. From the Actions Code Editor sidebar, select Test (play icon), then select **Run** to [test your code](/docs/customize/actions/test-actions).
    5. When you’re ready for the Action to go live, select **Deploy**.

    ##### Add your Action to the Login Flow

    Next, add the Action you created to the [Login Flow](https://manage.auth0.com/#/actions/flows/login/). To learn how to attach Actions to Flows, read the "Attach the Action to a flow" section in [Write Your First Action](/docs/customize/actions/write-your-first-action).

    ##### Retrieve the unique identifier

    Finally, from inside your API, retrieve the value of the claim from `req.auth`. Use that value as the unique user identifier to associate with timesheet entries.

    ```js lines
    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);
    });
    ```
  </Accordion>
</AccordionGroup>
