JavaScript: Calling an API

Gravatar for steve.hobbs@auth0.com
By Steve Hobbs

This tutorial demonstrates how to make API calls for protected resources on your server. We recommend that you log in to follow this quickstart with examples configured for your account.

I want to integrate with my app

15 minutes
  1. Create an API
  2. Create a Backend API
  3. Calling the API
Or

I want to explore a sample app

2 minutes

Get a sample configured with your account settings or check it out on Github.

View on Github

Most single-page apps use resources from data APIs. You may want to restrict access to those resources, so that only authenticated users with sufficient privileges can access them. Auth0 lets you manage access to these resources using API Authorization.

This tutorial shows you how to access protected resources in your API.

Create an API

In the APIs section of the Auth0 dashboard, click Create API. Provide a name and an identifier for your API. You will use the identifier later when you're configuring your Javascript Auth0 application instance. For Signing Algorithm, select RS256.

Create API

Create a Backend API

In this section, you will modify the ExpressJS that you created in part 1 so that it supports a new endpoint. This endpoint will require a valid access token to be sent in the Authorization header for the call to be successful.

Add middleware to the backend

To begin, let's install an NPM package that will be used to validate incoming tokens to the server. From the terminal:

npm install express-oauth2-jwt-bearer

Was this helpful?

/

Next, open server.js and bring in these libraries as imports at the top of the file. Also bring in the auth_config.json file so that the script can get access to the authentication credentials that have been configured:

// .. other imports

const { auth } = require("express-oauth2-jwt-bearer");
const authConfig = require("./auth_config.json");

Was this helpful?

/

Then add a call to auth(), which creates the middleware needed in order to validate and parse incoming access tokens. This should go after the require statements but before any routes are defined in your app:

// create the JWT middleware
const checkJwt = auth({
  audience: authConfig.audience,
  issuerBaseURL: `https://${authConfig.domain}`
});

Was this helpful?

/

This code configures the express-oauth2-jwt-bearer middleware with the settings that relate to your Auth0 application.

Next, open the auth_config.json file and modify the data so that the audience appears as a key within the JSON, using the value that you just used when creating the API:

{
  "domain": "{yourDomain}",
  "clientId": "{yourClientId}",
  "audience": "{yourApiIdentifier}"
}

Was this helpful?

/

The values for domain and clientId should have already been specified as part of the Login tutorial. They should point to the Domain and Client ID values for your Auth0 app respectively.

Add a protected endpoint

The last thing to do on the server side is to add an API endpoint that requires an access token to be provided for the call to succeed. This endpoint will use the middleware that you created earlier in the tutorial to provide that protection in a scalable way.

Open server.js and add a new route for /api/external above the other routes that returns some JSON:

// ..

app.get("/api/external", checkJwt, (req, res) => {
  res.send({
    msg: "Your access token was successfully validated!"
  });
});

// ..

Was this helpful?

/

Note that checkJwt is used as the second argument here. This causes checkJwt to be executed before the main route handler, and will reject the call and return a 401 response if:

  • there is no access token present in the Authorization header,
  • or the token itself is not valid

Finally, add an error handler so that a JSON response is returned from your API in the event of a missing or invalid token:

// ..

app.use(function(err, req, res, next) {
  if (err.name === "UnauthorizedError") {
    return res.status(401).send({ msg: "Invalid token" });
  }

  next(err, req, res);
});

//..

Was this helpful?

/

At the end, your server.js file will look something like the following:

const express = require("express");
const { auth } = require("express-oauth2-jwt-bearer");
const { join } = require("path");
const authConfig = require("./auth_config.json");

const app = express();

// Serve assets from the /public folder
app.use(express.static(join(__dirname, "public")));

// Create the JWT validation middleware
const checkJwt = auth({
  audience: authConfig.audience,
  issuerBaseURL: `https://${authConfig.domain}`
});

// Create an endpoint that uses the above middleware to
// protect this route from unauthorized requests
app.get("/api/external", checkJwt, (req, res) => {
  res.send({
    msg: "Your access token was successfully validated!"
  });
});

// Serve the auth configuration file
app.get("/auth_config.json", (req, res) => {
  res.sendFile(join(__dirname, "auth_config.json"));
});

// Serve the index page to everything else
app.get("/*", (req, res) => {
  res.sendFile(join(__dirname, "index.html"));
});

// Error handler
app.use(function(err, req, res, next) {
  if (err.name === "UnauthorizedError") {
    return res.status(401).send({ msg: "Invalid token" });
  }

  next(err, req, res);
});

module.exports = app;

Was this helpful?

/

Test the API

With this in place, run the application using npm run dev. In another terminal window, use the curl tool to make a request to this API endpoint and observe the results:

curl -I localhost:3000/api/external

Was this helpful?

/

You should find that a 401 Unauthorized result is returned, because it requires a valid access token:

HTTP/1.1 401 Unauthorized
X-DNS-Prefetch-Control: off
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'
Content-Type: text/html; charset=utf-8
Content-Length: 1582
Date: Wed, 03 Apr 2019 13:10:43 GMT
Connection: keep-alive

Was this helpful?

/

Calling the API

Now you can turn your attention to the front-end application. You will update the application to provide a button to call a function which will in turn call the API that you created in the previous section.

Open index.html and add a new button that will invoke the API call, as well as a pre element with an ID of api-call-result to show the result of the API call in the browser:

<button id="btn-call-api" disabled="true" onclick="callApi()">Call Api</button>

<!-- Add a container to hold the response from the call -->
<pre id="api-call-result"></pre>

Was this helpful?

/

Next, open public/js/app.js. Configure the auth0 client object to specify the audience value that was added earlier to the auth_config.json file:

const configureClient = async () => {
  const response = await fetchAuthConfig();
  const config = await response.json();

  auth0 = await auth0Client.createAuth0Client({
    domain: config.domain,
    clientId: config.clientId,
    authorizationParams: {
      audience: config.audience   // NEW - add the audience value
    }
  });
};

Was this helpful?

/

Add a new function called callApi to app.js, with the following content:

const callApi = async () => {
  try {

    // Get the access token from the Auth0 client
    const token = await auth0Client.getTokenSilently();

    // Make the call to the API, setting the token
    // in the Authorization header
    const response = await fetch("/api/external", {
      headers: {
        Authorization: `Bearer ${token}`
      }
    });

    // Fetch the JSON result
    const responseData = await response.json();

    // Display the result in the output element
    const responseElement = document.getElementById("api-call-result");

    responseElement.innerText = JSON.stringify(responseData, {}, 2);

} catch (e) {
    // Display errors in the console
    console.error(e);
  }
};

Was this helpful?

/

Finally, find the updateUI function within app.js and modify it so that the button for calling the API is enabled when the user logs in:

// public/js/app.js

const updateUI = async () => {
  const isAuthenticated = await auth0Client.isAuthenticated();

  document.getElementById("btn-logout").disabled = !isAuthenticated;
  document.getElementById("btn-login").disabled = isAuthenticated;

  // NEW - enable the button to call the API
  document.getElementById("btn-call-api").disabled = !isAuthenticated;

  // .. other code omitted for brevity ..
};

Was this helpful?

/

Now, open the browser in the application at http://localhost:3000. If the application has been stopped, run it again from the terminal using npm run dev.

When the application starts, log in. Then, press the Call API button to make a request to the API and put the results on the screen. You should find that the result from the server is displayed on the page.