DEV Community

Victoria Lo
Victoria Lo

Posted on • Originally published at lo-victoria.com on

Introduction to REST API Authentication Methods

Hello devs! In this article, I'll be discussing some common ways to authenticate your API as a way to protect your routes from users that shouldn't access them.

Why should I protect my routes?

Certain routes such as your user's profile page or the admin pages should be only accessible to that user or the admin himself respectively. Imagine being able to log into any user account on an app and see their private account data. That's just terrifying!

Therefore, it is necessary to protect routes with the authentication and authorization methods for your Node.js REST APIs. For this article, I will be demonstrating authentication only but I may write about authorization in the future because that topic deserves its own article. Before we get into the authentication methods, I first

Authentication vs Authorization

First, let's clarify some definitions: authentication and authorization. The table below is an easy-to-read overview of the differences between authentication and authorization. Please take your time to read and understand it before moving on.

Authentication Authorization
Determines whether users are who they claim to be Determines what users can and cannot access
Challenges the user to validate credentials (for example, through passwords, answers to security questions, or facial recognition) Verifies whether access is allowed through policies and rules
Usually done before authorization Usually done after successful authentication
Generally, transmits info through an ID Token Generally, transmits info through an Access Token
Example: Employees in a company are required to authenticate through the network before accessing their company email Example: After an employee successfully authenticates, the system determines what information the employees are allowed to access

(Source: auth0.com)

So now that you have a good understanding about authentication and authorization, I shall present 3 common authentication methods for REST APIs.

1. HTTP Basic Authentication

This is the simplest way to authenticate users. The request sends credentials such as username and password in the form of username:password to the header. It is encoded with Base64 and passed in the Authorization header like so:

Authorization: Basic AKsdKfsdljOf1POs
Enter fullscreen mode Exit fullscreen mode

basic

Example Implementation

Here's an example checkAuth middleware function that act as a gatekeeper before letting a user access a route.

const checkAuth = (req, res, next) => {
  //get the authorization header that was sent by the client
  const auth = req.headers["authorization"];

  /*
  auth = "Basic <encoded username:password>"
  get userpass via split and access index 1
  */
  const userpass = auth.split(" ")[1];

  //decode userpass to "username:password"
  const text = Buffer.from(userpass, "base64").toString("ascii");

  //get username and password individually
  const username = text.split(":")[0];
  const password = text.split(":")[1];

  if (username == process.env.USERNAME && password == process.env.PASSWORD) 
  {
    //auth successful, access to the route is granted
    return next();
  } else {
    //username and password is wrong, auth unsuccessful
    return res.json("Access Denied.");
  }
};
Enter fullscreen mode Exit fullscreen mode

When should Basic Header Authentication be used?

This authentication method may be the simplest, but it is also the most vulnerable since base64 encoding is easily reversible. HTTPS/TLS must be used with basic authentication. Because it is easy to implement and supported by most browsers, it is best used for server-side only applications. It can also be combined with other security methods to make it more secure.

2. JWT (JSON Web Tokens)

Just like the Basic Header Authentication, JWT also pass a credential in the Authorization header. The difference is that the credential is the form of the token and that it can expire. And, you need to install it with:

npm install jsonwebtoken
Enter fullscreen mode Exit fullscreen mode

Then import it to your server.js and controllers.js with the line:

const jwt = require("jsonwebtoken");
Enter fullscreen mode Exit fullscreen mode

A token is generated using a payload and a secret key that is encoded in Base64. Then it is stored and passed into the Authentication header with the Bearer instead of Basic schema, whenever the user logs in like so:

Authorization: Bearer JWT_TOKEN
Enter fullscreen mode Exit fullscreen mode

The middleware then verifies the authentication header and signs the user in, if the token and secret are correct of course. Here's a snapshot of the process visually.

jwt-diagram.png

Example Implementation

The secret key is stored in the project's .env file while the payload is an object, usually stored in a database like:

{
  "username": "John Doe",
  "password": 12345678
}
Enter fullscreen mode Exit fullscreen mode

To generate a JWT token, here's an example function:

function generateAccessToken(payload) {
  // expires after 1800 seconds (30 minutes)
  return jwt.sign(payload, process.env.SECRET_KEY, { expiresIn: '1800s' });
}
Enter fullscreen mode Exit fullscreen mode

We can call this function when the client supplies a username and password to the request body and sends it to an endpoint like:

app.post('/user/login', (req, res) => {
  const username = req.body.username;
  const password = req.body.password;

  //call the function to generate and then return the token
  const token = generateAccessToken({ username: username, password: password });
  res.json(token);
});
Enter fullscreen mode Exit fullscreen mode

The token is usually stored in cookies or localStorage. After generating the token, we can verify it in the Authorization header whenever the user logs in.

function authenticateToken(req, res, next) {
  //Get the request header that was sent
  const auth = req.headers['authorization'];
  /*
  auth = "Bearer <token>"
  so get the token by split and at index 1
  */
  const token = auth.split(' ')[1];

  // if there isn't any token, send unauthorised status
  if (token == null) return res.sendStatus(401) ;

  //verify the token with the secret key
  jwt.verify(token, process.env.SECRET_KEY, (err: any, user: any) => {

    //if user is not in the database
    if (err) return res.sendStatus(403);
    //else access is granted
    return next();
  })
}
Enter fullscreen mode Exit fullscreen mode

When should JWT Authentication be used?

This authentication method is suited for most app authentication needs. It can be used for mobile, web or server side apps. They work well with Express or apps with MVC architecture.

JWTs are stateless, all the information needed to authenticate a user is within that token. Keep in mind that the token is sent every time a request is made. For enterprise apps, this could impact the data traffic size, as there would be multiple access levels, permissions and other roles to think about when implementing a solution with JWT.

Another important note is that the token has to be explicitly stored somewhere. Don't store it in sessionStorage or localStorage, which are both susceptible to XSRF (Cross-Site Request Forgery) or XSS (Cross-Site Scripting) attacks. That is why it is a good idea to keep the expiry dates on the tokens short and store them server-side instead.

3. OAuth 2.0

The final authentication method we'll be discussing in this article is OAuth 2.0. Rather than a method, it is more of an authorization framework commonly used for apps with 3 parties: you, the users and the third party developers. For example:
oauth

As seen from this screenshot, instead of directly creating a Spotify account and signing in to their app with user credentials, the user is allowing Facebook (a third party) to verify his credentials to authenticate himself to access user exclusive routes in Spotify.

In short, OAuth 2.0 works by delegating authentication to an authorization server (i.e. Facebook, Google, Github, etc.) that hosts the user account. The server then generates a token and sends it to the resource server (i.e. Spotify or an API) to authorize the user to access protected routes.

See the illustration below to get a better picture.

slack

Example Implementation

There are many services that uses this framework such as Firebase Authentication, DigitalOcean, Amazon Cognito and so on. I personally use Firebase because it is easy and intuitive to use.

firebase

You can check out how I implemented a Firebase Authentication system in a React app in this article.

When should OAuth 2.0 be used?

Like mentioned earlier, it should be used when an app has 3 parties involved. When implementing OAuth, it is also good to provide your own basic email or username authentication, just in case the user doesn't want to allow external third party services to access their data. You probably see this practice done often like the screenshot below.

eg

Summary

Today, we have discussed the difference between authentication and authorization, and how we can implement some common authentication methods such as Basic Header, JWT Authentication and OAuth 2.0 to our REST APIs or apps.

Thanks so much for taking the time to read this article. I hope it has been insightful for you. Please do give a like or a share if it is! Building is always the best way to learn so I recommend trying to build an app with user authentication to learn a more of each authentication method and get a better understanding on how they work. To learn more, feel free to read the resources below. Till next time, cheers!


See Also

Image Credits:

Top comments (0)