How to Authenticate using Keys, BasicAuth, OAuth2 in JavaScript
Tags: javascript, programming, codenewbie, 100daysofcode
Published: 2021-06-27 08:30:50

*Originally Posted on [realpythonproject.com](https://www.realpythonproject.com/how-to-authenticate-using-keys-basicauth-oauth2-in-javascript/)*

<p><em>Connect with me on </em><a href="https://www.linkedin.com/in/rahulbanerjee2699/" rel="noreferrer noopener" target="_blank"><em>LinkedIn</em></a><em>, </em><a href="https://twitter.com/rahulbanerjee99" rel="noreferrer noopener" target="_blank"><em>Twitter</em></a></p>



<!-- wp:paragraph -->
<p>Not all APIs are as well documented as Twilio. This guide should help you work with APIs which are secured using Keys, BasicAuth, or OAuth.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will be working with the following APIS</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><a href="https://dukengn.github.io/Dog-facts-API/">Dog Facts</a></li><li><a href="https://thecatapi.com/">Cat as a Service (CAAS)</a></li><li><a href="https://www.twilio.com/docs/usage/api">Twilio API</a></li><li><a href="https://docs.github.com/en/rest">GitHub API</a></li><li><a href="https://docs.genius.com/">Genius API</a></li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>If you are interested in a similar guide for Python, check out <a href="https://www.realpythonproject.com/how-to-authenticate-using-keys-basicauth-oauth-in-python/">my previous article.</a></p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Table of Contents</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>Insecure APIs</li><li>Reading values from.env files</li><li>APIs with Keys</li><li>APIs with Basic Auth</li><li>API Wrappers</li><li>APIs secured via OAuth2</li><li>Using the GitHub API (OAuth2)</li><li>Using the Genius API (OAuth2)</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Some familiarity with promises and async/await is expected. I will be running the code in a NodeJS environment.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You can find the source code <a href="https://github.com/rahulbanerjee26/javascript_apis">here</a></p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Insecure APIs</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The <a href="https://dukengn.github.io/Dog-facts-API/">Dog Facts APIs</a> does not require any authentication and is publicly available. It is fairly straightforward to work with it.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will be making a request to the following endpoint</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">https://dog-facts-api.herokuapp.com/api/v1/resources/dogs/all</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>First, we will need to install the node-fetch library</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install node-fetch</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Now, let's make a GET request to the above endpoint in javascript</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">const fetch = require("node-fetch");

const apiURL = "https://dog-facts-api.herokuapp.com/api/v1/resources/dogs/all";
console.log(`Making Request to ${apiURL}`);
fetch(apiURL)
  .then((result) => result.json())
  .then((res) => {
    res.map((element, idx) => console.log(`${idx}. ${element.fact}`));
  })
  .catch((err) => console.log(err));</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>We import the node-fetch library and make a request to the endpoint. We add a .then to resolve the Promise and a .catch to handle errors.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Reading from .env files</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Before moving on to the next sections, let's look at how to read variables from a .env file. It's highly recommended to store your credentials in a .env file to avoid them being exposed to others.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will need to install the 'dotenv' library</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install dotenv</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Assume we have a .env file with some random API Token</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">API_TOKEN = "SOME API TOKEN"</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Let's try reading the API Token in JavaScript.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">require('dotenv').config()

const API_KEY=  process.env.API_KEY</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":3} -->
<h3>APIs with Keys</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This is the most common form of authentication when consuming APIs. The API Key/Token is passed in as a header while making the request. We will be working with the <a href="https://thecatapi.com/">Cat as a Service (CAAS)</a> API. You can get a <a href="https://thecatapi.com/signup">key here</a></p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">const fetch = require("node-fetch");
require("dotenv").config();

const CAT_API_KEY = process.env.API_KEY;
const headers = {
  "x-api-key": CAT_API_KEY,
};
const api_url = "https://api.thecatapi.com/v1/breeds";

fetch(api_url, {
  headers: headers,
})
  .then((result) => result.json())
  .then((res) => {
    res.map((element, idx) =>
      console.log(`${idx}. ${element.name} : ${element.description}`)
    );
  })
  .catch((err) => console.log(err));</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>We created an object called <strong>headers</strong> to store the API Key. The key in the object is "x-api-key". However, this can differ based on the API you are working with. Some APIs require the key to be named "Authorization", "authorization", "token" ,etc. It is best to refer to your API's documentation's authentication section.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Bearer Authentication is pretty common and it requires the word "Bearer " (note the space) to be at the beginning of the API Token/Key.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">headers = {
    "authorization": f"Bearer {access_token}"
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>We will be using bearer authentication in an example in a later section.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>APIs with Basic Auth</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>An API secured using Basic Auth requires a username and password. Usually, the username is the Client ID and the password is the Client Secret of the API. In some cases, the username can be left blank. This should be mentioned in the API documentation.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The <a href="https://www.twilio.com/docs/usage/api">Twilio API</a> is secured using Basic Auth. You can sign up on the Twilio website and get access to the API credentials.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will be using the base-64 library, you can install it using npm</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install base-64</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The only difference is in the headers object will be passing while making the GET request. We will use a header object like below</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">headers = {
    'Authorization' : 'Basic ' + base64.encode(twilio_id + ":" + twilio_token)
}</code></pre>
<!-- /wp:code -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note there is a space after Basic</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>In the case of twilio, the username is your account sid and the password is your account token. As mentioned before, it can be different for different APIs. If the API you are using, uses Basic Auth to secure its endpoints, refer to the docs for the username and password.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now let's make a request to the twilio API</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">const fetch = require("node-fetch");
const base64 = require("base-64");

require("dotenv").config();
const twilio_id = process.env.TWILIO_ACCOUNT_SID;
const twilio_token = process.env.TWILIO_ACCOUNT_TOKEN;

headers = {
  Authorization: "Basic " + base64.encode(twilio_id + ":" + twilio_token),
};
const api_url = `https://api.twilio.com/2010-04-01/Accounts/${twilio_id}/Calls.json?PageSize=5`;

fetch(api_url, {
  headers: headers,
})
  .then((res) => res.json())
  .then((res) => console.log(res))
  .catch((err) => console.log(err));</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>As you can see, the code is pretty similar to the code we wrote when making a requests to the Cat API. The only difference being in the headers object.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>API Wrappers</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>API wrappers are essentially packages that can be installed using npm. They make interacting with APIs easier and make your code look cleaner. Under the hood, the package will use fetch and headers to authenticate your requests. However, the wrapper makes the code look cleaner.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Twilio has a wrapper which can be installed using npm</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install twilio</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Let's use the twilio wrapper to interact with the twilio API</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">const twilio = require('twilio')
require('dotenv').config()
const twilio_id = process.env.TWILIO_ACCOUNT_SID
const twilio_token = process.env.TWILIO_ACCOUNT_TOKEN

const client = new twilio(twilio_id,twilio_token)
client.calls.each(call => console.log(call),pageSize = 5);</code></pre>
<!-- /wp:code -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afqhpfj1iqqagshplhf6.png" alt="Desktop - 1"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>For handling errors, we could put the code inside the try..catch block.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Unfortunately, not all APIs have a wrapper. However, a lot of them do. Before a consuming an API directly, try searching for a wrapper for it. This will make it significantly easier to work with the API.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>APIs secured via OAuth2</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Using OAuth2 web flow to authenticate is usually used in Express apps when you need a "Sign Up using Google", "Sign Up using Facebook" option. However, some APIs need OAuth2 for all their endpoints. The GitHub API supports OAuth2 authentication as well as Key based authentication. In this article we will be using the OAuth web flow to work with the GitHub API and the Genius API.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>I won't be going too much into detail on how OAuth2 works since that is beyond the scope of this article. Below is a high-level overview. If it doesn't make sense, skip over to the Github or Genius API section and it should make more sense.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>We will have to create a client app on the API's website</li><li>The client app will have a client ID and Client Secret</li><li>We will have to make a request to the API's authentication endpoint. The client ID and client Secret will be passed as query parameters.</li><li>The authentication endpoint will ask for permission and will have to be authorized</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621834748368/rAqcrxCnA.png" alt="google-oauth-consent.png"/></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Once authorized, it will return a code</li><li>This code will have to be given to another endpoint which will exchange it for an access token.</li><li>This access token can now be used as a key and be passed as a header object when making requests to the endpoint.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Let's take a look at a couple of examples.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Using the GitHub API (OAuth2)</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>As mentioned above, OAuth2 is mostly used with Express APPs. When working with OAuth2, you will need a web app URL and a URL to redirect the user to once they authorize/give permission. Since we do not have a web app, we do not have any URL. However we can use <a href="https://httpbin.org/">HTTPBin</a>. Whenever we need an URL, we can use the following URL</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">https://httpbin.org/anything</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>First, you will have to <a href="https://docs.github.com/en/developers/apps/building-github-apps/creating-a-github-app">create a GitHub App</a>. When asked for the web app URL or the redirect URL, use the above-discussed URL. Once you have created the app, store the Client ID and Client Secret in the .env file.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We will write our code using async/await to make it more readable.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">  const client_id = process.env.GITHUB_API_CLIENT_ID;
  const client_secret = process.env.GITHUB_API_CLIENT_SECRET;
  const redirect_uri = "https://httpbin.org/anything";

  let params = {
    client_id: client_id,
    redirect_uri: redirect_uri,
    scope: "user",
  };

  let endpoint = "https://github.com/login/oauth/authorize?";
  endpoint = endpoint + new URLSearchParams(params);

  const open = require("open");
  open(endpoint);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The first few lines are simply reading the credentials from our .env file. The params object contains the client ID, the redirect URL which is the HTTPBin URL we discussed earlier and the scope. The value of the scope determines the endpoints you can access and the HTTP Verb Actions you can do.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To add the parameters to our URL, we can use URLSearchParams. To open the url, we will use the open() function. It can be installed using npm</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install open</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Once you click authorize, you should be redirected to the HTTPBin URL and a JSON Object should be displayed. Look at the value for the key "code". This value will be exchanged for an API Token.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621835203410/KSc4uGKH1.png" alt="Screen Shot 2021-05-24 at 1.36.59 AM.png"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>We can use the 'readline-sync' to take an input.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install readline-sync</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>We will wait for the user to input their access code</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">  const readlineSync = require("readline-sync");
  const access_code = readlineSync.question("Please enter the access code ");
  console.log("CODE IS ", access_code);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Once, we get the code, we make another request to an endpoint to get an access token. This time we pass the code along with the client secret as parameters. After GitHub validates the credentials along with the code, it will return an access token. This access token can be used as an API Key.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">  params["client_secret"] = client_secret;
  params["code"] = access_code;
  const access_token_url = "https://github.com/login/oauth/access_token?";
  let response = await fetch(access_token_url + new URLSearchParams(params), {
    headers: { Accept: "application/json", method: "POST" },
  });
  let data = await response.json();
  const access_token = data["access_token"];
  console.log(access_token);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>This access token can be used to authenticate ourselves and make requests to the API Endpoints.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">  const headers = {
    Authorization: `token ${access_token}`,
  };

  const base_api_endpoint = "https://api.github.com/user";
  response = await fetch(base_api_endpoint + "/repos", {
    headers: headers,
  });
  data = await response.json();
  console.log(data);</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":3} -->
<h3>Using the Genius API (OAuth2)</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Let's take a look at another example. I'll skip the part where we import the packages and read the credentials.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript"> let params = {
    client_id: genius_client_id,
    redirect_uri: redirect_uri,
    response_type: "code",
    scope: "me",
  };

  let endpoint = "https://api.genius.com/oauth/authorize?";
  endpoint = endpoint + new URLSearchParams(params);

  const open = require("open");
  open(endpoint);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The "response_type" is mandatory for some APIs, the value should always be "code"</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621835658537/wXxE5TLIl.png" alt="Screen Shot 2021-05-24 at 1.54.05 AM.png"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>After we authorize, we will see a JSON object similar to the one we saw when working with the GitHub API. Input the Code.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="javascript" class="language-javascript">  const readlineSync = require("readline-sync");
  const access_code = readlineSync.question("Please enter the access code ");
  console.log("CODE IS ", access_code);

  params["client_secret"] = genius_client_secret;
  params["code"] = access_code;
  params["grant_type"] = "authorization_code";

  const access_token_url = "https://api.genius.com/oauth/token?";
  let response = await fetch(access_token_url + new URLSearchParams(params), {
    headers: { Accept: "application/json" },
    method: "POST",
  });
  let data = await response.json();
  const access_token = data["access_token"];
  console.log(access_token);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>"grant_type" is also required by some APIs. The value is always "authorization_code". After our code is validated, we get an access token. This token can be used as an API Key.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code class="">  const headers = {
    authorization: `Bearer ${access_token}`,
  };

  const base_api_endpoint = "https://api.genius.com/account";
  response = await fetch(base_api_endpoint, {
    headers: headers,
  });
  data = await response.json();
  console.log(data);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The Genius API uses Bearer Authentication.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Conclusion</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>I hope this article serves as a good guide to work with APIs in JavScript. Before consuming an API directly, always look for a wrapper. The 5 mins you spend looking for a wrapper might save you hours of headache.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Connect with me on <a href="https://www.linkedin.com/in/rahulbanerjee2699/">LinkedIn</a>, <a href="https://twitter.com/rahulbanerjee99">Twitter</a></p>
<!-- /wp:paragraph -->