3-tier authentication - understand and conceptualize📸🤯 the process
Tags: architecture, beginners, node, django
Published: 2023-03-06 06:00:00

<small>Welcome to <b>part 1</b>. Follow along this series to develop a <em>feature-packed</em> 3-tier Authentication System outlined in successive parts.</small>

_**Summary:** In this article, we explore token-based authentication process in a three-tier web architecture plus the bare minimum security practices to emulate_.

<!-- Conceptualize the authentication flow in advanced web app -->
<!-- Authentication flow - Understanding the process -->
<!-- 3-tier Authentication flow - Understanding the process -->

<details>
  <summary><b>Table of Contents</b></summary>
  <ol>
    <li><a href="#intro">Intro</a></li>
    <li><a href="#what-is-this-tier-thing">What is this tier thing?</a></li>
    <li><a href="#authentication-in-threetier-architecture">Authentication in three-tier architecture</a></li>
    <li><a href="#how-it-works">How it works</a>
		<ul>
			<li><a href="#log-in">Log in</a></li>
			<li><a href="#accessing-protected-resources">Accessing protected resources</a></li>
			<li><a href="#refreshing-access-token">Refreshing Access Token</a></li>
		</ul>
	  </li>
    <li><a href="#security-practices">Security practices</a></li>
    <li><a href="#run-down">Run down</a></li>
  </ol>
</details>

## Intro

User **authentication** and **authorization** are core _information security processes_ in building secure systems. **_Authentication_** verifies the identity of a user or service before they can proceed to access protected resources. **_Authorization_** determines what access level is required to access protected resources, _even after you are authenticated_.

Modern software is built in parts, a design commonly reffered to as **N-tier web architecture**. Also called _Multi-tier architecture_. A common form of **N-tier** architecture is the **Three-tier architecture**. The name _N-tier_ is coined because systems do not have to be restricted to _three tiers, for example_. As complexity increases, it is common to have more tiers.

## What is this tier thing?

I hope my guess is right. You may be wondering what is a tier?

Well, probably you have heard of **MERN** if not **MEAN**, **MEVN**, ... These are just a combination of technologies(<small><i>that somehow became popular</i></small>). What is not coming out clearly is that we have **layers** when building software systems. Infact, we are reffering to **tiers**...not **layers**.

For instance, let us elaborate using the MERN stack.<br />
You have a front-end built using **Reactjs**. A combination of **Nodejs** and **Expressjs** to build a backend that is using **MongoDB** as database storage. Typically your architecture here is a **Three-tier architecture** with the following tiers:

-   Presentation tier - The UI/front-end. (Reactjs)
-   Application tier - Also called the _logic tier_ or _middle tier_. Where business logic for your app lies. (Node/Express)
-   Data tier - Sometimes called _database tier_. Where information processed in the _application tier_ is stored/managed. (MongoDB)

You should see that tier is like a layer. But it is called a tier because: **_"layer"_** is only a functional division of software, while a **_"tier"_** refers to **a functional division of a software that runs on infrastructure separate from the other divisions**. For example MongoDB runs on a separate infrastructure from Node/Express.

## Authentication in three-tier architecture

Whether you want to increase your internal security, improve consumer acquisition or provide a better user experience for your site visitors, it's essential to know how user authentication fits into the equation.

It's fairly easy to get the ball rolling using bold _tech-stacks_ like **MERN**. An outright challenge is the topic of authentication. It can be daunting to put together authentication for such a project; considering that it has parts running in separate infrastructure yet they have to work together **to achieve a common goal**. Moreso being _unopinionated_.

A bullet-proof authentication is critical about incorporating best secure practices regularly replacing the phased-out ones. This gives a solid reason one may opt for authentication providers <i>e.g Auth0, Cognito, Firebase Auth</i>, who have specialized in the authentication domain to fast-track security vulnerabilities.<br />
However, there are justifiable reasons to <span id="why-build-auth"><b>implement your own Authentication</b></span>, for example:

-   You want to know how authentication works(_not only using it_).
-   You want user data to remain within your application.
-   You want a bespoke authentication solution that integrates with infrastructure component that is unique to your bussiness.
-   Your application has a low-security risk.
-   You want to avoid/reduce vendor licensing fees.
-   You do not want to induce points of failure with less control over it when you should be able to deal with such issues.
-   If the third party service at the core of your architecture decided to shut you down or compete with you or shut down themselves, then you become grounded.
-   Not all users are comfortable with trusting a third party in order to use your application.

In this article we are considering a bespoke Authentication solution. We articulate a conceptual flow of a typical authentication process.

The type of authentication conceptualized here is **Token-based authentication** using [Json Web Tokens](https://jwt.io). This is a popular authentication protocol between <em>Single Page Applications(SPA<small>s</small>)</em> and <em>REST API<small>s</small></em>.

## How it works

In **Token-based authentication**, the server application generates authentication tokens, _i.e **access token** and **refresh token** pair_ after login credentials have been successfully verified. Then clients requesting to protected resources on the server are required to include access token in every HTTP request.

**Access token:** Is a _Json Web Token_ issued to a correctly logged-in user. It contains _insensitive_ user information embedded in it. This token needs to be provided when accessing a protected resource on the server.

**Refresh token:** Is a _Json Web Token_ also issued after successful login. HTTP request may need to get a **new access token** since a server will reject an _access token that is expired/invalid_. A _refresh token_ **needs** to be included on such a request before the server can process it to provide a new access token.

We'll look at the following processes in a Token-based authentication:

-   Log in
-   Accesing protected resource
-   Refreshing _access token_

Let's reflect on the login process.

### Log In

Below is a visualization of a login flow.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xdpdgd69k36uqgql9o46.gif" alt="Login flow" />
  <figcaption>Login flow</figcaption>
</figure>

<!--
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibjeha2xiaxxetktjr5s.gif
<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8nt90uu4ep8fvb1gw5gd.png" alt="Login Authentication flow" />
  <figcaption>Login Authentication flow</figcaption>
</figure>
-->

In a nutshell, the purpose of login is to _request to be authenticated_, facilitated by an access token being sent back after successful login verification. This token is what you need in every HTTP request to gain access on protected resources on the server. Including a _valid_ access token renders a HTTP request as authenticated.

The flow of login control would be like:

-   The client submits _"username"_ and _"password"_ to the server.

-   The server receives login credentials and verifies them against a database.
-   Once a match is found, signed _access_ & _refresh tokens_ are generated. These tokens are embedded with **insensitive** information from the match found.
-   The server returns a response including the access token and refresh token.

_**Note:** In the visual illustration above, access token is returned in the **response body** while refresh token is returned in the **response header**. The assumption is that the client is in browser environment and refresh token is set onto the **HTTP only cookie** to help with secure storage of the credentials(access & refresh token) from the client-side._

### Accessing protected resources

Probably we have already stressed that accessing a protected resource on the server requires that you provide an access token sent along with the HTTP request. Like shown below:

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/exhaotspqjy0cgdkfgpm.gif" alt="Protected Resource Access flow" />
  <figcaption>Protected Resource Access flow</figcaption>
</figure>
<!-- <figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygadd4fgqntiqcflgxkn.png" alt="Protected Resource Access flow" />
  <figcaption>Accessing Protected Resource flow</figcaption>
</figure> -->

To access a protected resource, the flow would be:

-   Client attaches _access token_ on `Authorization` header of a HTTP request.
-   Server checks for the credential(_access token_) in the `Authorization` header.
-   Validation and verification is run on the _access token_.
-   Once successfully verified, server allows protected resource to be served.

A step that fails will make the server to respond with an _unauthenticated error_ commonly depicted with a `401` HTTP status code.

### Refreshing Access Token

We have not talked much about _refresh token_. It is a big player when we want to refresh/renew _access token_. The rule of the thumb about _Token-based authentication_ is that generated token pair **should expire**. _Access token_ should have the **shorter time to expiry** than _refresh token_.

**Without** a _refresh token_, a user would be interrupted to _"log in"_ again with _username/password_ to obtain a new _access token_ whenever the current one becomes invalid or expired. That rude interruption is an annoying experience to a user considering that _access token_ is short-lived.<br />
**With** a _refresh token_, client can obtain a new _access token_ without another manual _"log in"_. And for a better user experience, a client will _automatically obtain a NEW access token in the background_ whenever a server rejects the _access token_ in HTTP request because it is _invalid or expired_. The rejected request can then be _retried_ with the **NEW access token**. All these is automated by a client without a user's intervention.<br />
This process is as visualized below:

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lazik5ck31zkt8pdg176.gif" alt="Refresh Access token overview" />
  <figcaption>Refresh Access token overview</figcaption>
</figure>
<!-- <figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s5q9q6fxms4uce3vl3v3.gif" alt="Refresh token flow" />
  <figcaption>The flow of refreshing Access Token</figcaption>
</figure> -->

Procedurally:

-   A client includes access token in `Authorization` header of HTTP request.
-   This is a protected resource, so the server checks for _access token_ in `Authorization` header.
-   Server authenticates the request and detects _access token_ is expired(or invalid).
-   Server ends the request with an **unauthenticated error** response.
-   Client detects that the request failed due to unauthentication.
-   Client triggers a HTTP request to renew _access token_ and includes _refresh token_ in cookie header.
-   Server verifies the _refresh token_.
-   Once _refresh token_ is verified, a NEW access token is generated and returned in response body.
-   Client receives the _NEW access token_.
-   Client uses the NEW access token to retry the initial request that had failed with an _unauthenticated error_.

_**Note:** Maximum retries should be implemented on the client-side to avoid an infinite loop_.

## Security practices

The stateless principle of _Token-based authentication_ is advantagious to give your application the performance boost you just needed. This is because there is no database look-ups when authenticating requests. _Access tokens_ are stored on the client-side. Same is the case for _refresh tokens_.

However since these tokens are as sensitive as _"passwords"_, they need to be stored securely from the client-side. You should consider implementing the following best practices:

1. Do not embed sensitive data in the tokens.
1. Give tokens an expiration.
1. Access tokens should be short-lived(_within minutes_). While maintaining the stateless characteristic, _access tokens **do not** have a way to be revoked_. A short life span will allow for minimal duration of usage incase an access token lands in the hands of _"evil"_ user.
1. Refresh tokens should be _revocable_. Since there is no way to revoke access tokens, then at least _refresh tokens should_. If a refresh token is reported as leaked, the token can be revoked such that refresh requests using the revoked _refresh token_ **will fail**. Possibly you could think of an evil user using a stolen access token and next time they want to renew the token, the server will lock them out.
1. Incase client is in a browser environment, _refresh tokens_ could be stored in HTTP-only cookie and _access token_ kept _in-memory_ without persisting anywhere.

## Run down

We have discussed the process of authentication and the steps involved in a typical _"Three-tier web architecture"_. To quickly recap, we have discussed the following:

-   Modern software is built in parts with different infrastructure(tiers).
-   Token-based authentication is common among _N-tier architectured_ applications.
-   Login is a request to get authentication tokens.
-   Access token and refresh token are issued after successful login.
-   Authentication tokens issued are stored in the client-side. And they should be stored securely.
-   Requests to protected resources on the server need to include access token e.g in `Authorization` header.
-   Refresh token is used to renew _access token_.

And that's a wrap. Thanks for reading this far. Are you one that wants the concepts shared here translated into working solution? If it sounds like you, this series just serves you right. Check ou the next parts.

---

<em>
Something is not clear enough? Don't hesitate to bomb💣 the comment section👇️. The explosion effect can clear your mysteries. Also reach out <a href="https://twitter.com/intent/user?screen_name=smitterhane" rel="noopener">@twitter</a>. I'll be happy to help 😊.
</em>