Welcome to part 1. Follow along this series to develop a feature-packed 3-tier Authentication System outlined in successive parts.
Summary: In this article, we explore token-based authentication process in a three-tier web architecture plus the bare minimum security practices to emulate.
Table of Contents
- Intro
- What is this tier thing?
- Authentication in three-tier architecture
- How it works
- Security practices
- Run down
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(that somehow became popular). 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.
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 e.g Auth0, Cognito, Firebase Auth, who have specialized in the authentication domain to fast-track security vulnerabilities.
However, there are justifiable reasons to implement your own Authentication, 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. This is a popular authentication protocol between Single Page Applications(SPAs) and REST APIs.
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.
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:
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.
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.
This process is as visualized below:
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:
- Do not embed sensitive data in the tokens.
- Give tokens an expiration.
- 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.
- 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.
- 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.
Something is not clear enough? Don't hesitate to bomb💣 the comment section👇️. The explosion effect can clear your mysteries. Also reach out @twitter. I'll be happy to help 😊.
Top comments (2)
This is amazing! Thank you for your work!
Welcome again @losinigo
Glad you found it useful