You don’t need another session and token authentication article, but I still wrote one

tpc_deadlock
4 min readJul 18, 2021

So I’ve been trying to clear out the concepts of sessions, cookies, tokens, web authentications, etc. for quite some time now. It’s finally reached a point where I believe I should jot down some texts about the topic. Usually, when we developers talk about this topic, we use terms interchangeably in situations when terms are not identical sometimes, which unluckily has given me confusion every now and then. After reviewing some articles and videos, I feel that it might be easiest to talk about two major authentication approaches as a starting point for a potentially long journey for web-related authentications. Let me introduce you to session-based authentication and token-based authentication.

Session-based Authentication

In this approach, the authentication process is based on a session that is stored on the server-side either in memory or in the database. As we know, HTTP protocol is stateless (By design, the server doesn’t remember anything about the client’s state), the session in this case helps the server and client achieve so-called stateful communication.

Here is the flow for session-based authentication.

  • client — —logs in with user name, password — — → server
  • server stores session data
  • client < — — sends the cookie to the client (session-id: abc) — — server
  • client — —sends auth request such as GET (session-id: abc in the cookie) — → server
  • server compares session-id with the data stored in its memory / DB
  • client < — — sends response on every subsequent request — — server

A session starts from a login activity when a user sends user info to the server, in which a session is created. After that, the client and server talk to each other with the help of a session-id, which is wrapped in the cookie header of the server’s response. This cookie is stored in the client’s browser, When the user logs out, the session data is deleted from the server-side and the session ends.

Token-based Authentication

A typical choice for token-based authentication is by using JWT (JSON Web Tokens). In this method, the token is not stored on the server-side, instead, it’s stored on the client-side in localStorage (mostly). The client sends further requests along with the token and the server validates the token.

Here is the flow for JWT authentication.

  • client — — logs in with user name, password — → server
  • server creates an encrypted JWT for the user
  • client < — — sends encrypted to the client — —server
  • client — — sends Auth requests with JWT in header — → server
  • server compares JWT and verifies if it’s valid
  • client < — — sends response on every subsequent request — — server

The request with a token in the header that is sent to the server looks like this:

{  
method: "GET",
headers: {
"Authorization": "Bearer ${JWT_TOKEN}"
}
}

Notice that the token value starts with Bearer, the server needs to remove this prefix when verifying the token value.

It’s the client’s responsibility to maintain and delete the token at the right time, it’s an easier and lighter approach, considering there is no server-side storage needed, however, it sometimes introduces the problem of a compromised secret key. Sensitive information should also be avoided to be included in JWT since it can be encrypted easily.

Refresh Token vs. Access Token

Another interesting and fairly important concept is token types. The two most common types of tokens are refresh tokens and access tokens. Sometimes it’s confusing for developers to tell one from the other since they’re both just pieces of data authorizing users in request-response type of communication. If we look at the explanation in this auth0’s blog:

Access tokens carry the necessary information to access a resource directly. In other words, when a client passes an access token to a server managing a resource, that server can use the information contained in the token to decide whether the client is authorized or not. Access tokens usually have an expiration date and are short-lived.

Refresh tokens carry the information necessary to get a new access token. In other words, whenever an access token is required to access a specific resource, a client may use a refresh token to get a new access token issued by the authentication server. Common use cases include getting new access tokens after old ones have expired, or getting access to a new resource for the first time. Refresh tokens can also expire but are rather long-lived. Refresh tokens are usually subject to strict storage requirements to ensure they are not leaked. They can also be blacklisted by the authorization server.

Note that there are 3 roles in a flow involving refresh tokens and access tokens.

  • Client: asks resource server for resources, asks auth server for a new access token.
  • Auth server: receives a refresh token from the client, sends back a new access token.
  • Resource server: receives request with access token from the client, validates it, and sends back protected resources.

Compared to access tokens, refresh tokens have a longer expiration period. We can easily define the expiration time span in different languages or web frameworks, for example:

type User { ... }  export const createRefreshToken = (user: User) => {   
return sign(
{ userId: user.id },
process.env.REFRESH_TOKEN_SECRET!,
{ expiresIn: '7d' }
);
};
export const createAccessToken = (user: User) => {
return sign(
{ userId: user.id },
process.env.ACCESS_TOKEN_SECRET!,
{ expiresIn: '15m' }
);
};

Next step, let’s talk about the security and scalability considerations of these two scenarios, and how and when you should choose one over the other.

--

--

tpc_deadlock
0 Followers

Self-maintainable limbs. I program and I write.