🔐 Session-Based vs. Token-Based Authentication: Which is better?🤔
Fidal Mathew
Posted on December 23, 2023
Hi fellow readers!✋ I hope you’re doing great. In this article, we will learn about session and token-based authentication methods used in backend applications. Let’s take a look at them.
🔐 Session-based auth
In simple words, session-based authentication uses a special code(session id) stored on your device to remember who you are when you visit a website, keeping you logged in and remembering your information until you leave or log out. Didn’t get it? Don’t worry, let’s take a look step by step.
1. User Login:
Users log in by sending their email and password to the server through a special request.
2. Checking Details:
The server checks if the provided details match what's stored for the user.
3. Creating a Session:
If everything is correct, the server makes a 'session' that holds user info (like user ID, permissions, and time limits). This info is kept safe in the server's storage. Exam or can also be managed using libraries such as express-session
.
4. Getting a Session ID:
The server sends this 'session ID' back to the user's device, usually as a cookie in the response.
5. Using the Session ID:
Whenever the user wants something from the server, their device automatically includes this session ID in its requests.
6. Server Checks:
The server uses this session ID to find the stored information about the session user in the session storage.
Here’s a sneak peek at how express-session
works:
When the user logs in, the server creates a session for that user and sets a cookie🍪 in the response containing the session ID.
The browser automatically includes this session ID cookie🍪 in subsequent requests to the server.
When the server receives a request, express-session middleware uses the session ID from the cookie🍪 to retrieve the relevant session data.
The data stored in req.session (such as userId) becomes available to handle the request.
7. Access Granted:
If everything matches up, the server knows the user is genuine and responds to them with access to what they asked for.
Example
Here's an example of a Node.js application using Express.js to implement session authentication.
Implementation
const express = require('express');
const session = require('express-session');
const app = express();
// Middleware setup
app.use(session({
secret: 'your_secret_key',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true, // Set the cookie as HTTP-only, Optional
maxAge: 60*30 // In secs, Optional
}
}));
Login route
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (user) {
req.session.userId = user.id; // Store user ID in session
res.send('Login successful');
} else {
res.status(401).send('Invalid credentials');
}
});
Protected route
app.get('/home', (req, res) => {
if (req.session.userId) {
// User is authenticated
res.send(Welcome to the Home page, User </span><span class="p">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">userId</span><span class="p">}</span><span class="s2">!
);
} else {
// User is not authenticated
res.status(401).send('Unauthorized');
}
});
Logout route
app.get('/logout', (req, res) => {
req.session.destroy(err => {
if (err) {
res.status(500).send('Error logging out');
} else {
res.redirect('/'); // Redirect to the home page after logout
}
});
});
🔐 Token-based auth
JWT authentication uses digitally signed tokens containing user information to allow secure and verified access to websites or applications without needing to repeatedly log in. Let’s take a look at the step-by-step workflow of token-based authentication.
1. User Login Request:
Users log in by sending their email and password to the server through a specific request.
2. Credential Verification:
The server verifies the provided credentials against the stored user data.
3. Token Generation:
Upon successful verification, the server creates a token (commonly JWT - JSON Web Token). This token holds user information (claims) such as user_id, permissions.
4. Token Signing and Hashing:
The token is signed with a secret key and processed with a hashing algorithm (like SHA256) to create a hash.
5. Sending the Token:
The server sends this token to the client, which stores it, typically in the browser.
6. Token Storage Options:
The client can store the token in different ways like HttpOnly Cookies, Session Storage, or Local Storage. Storing in HttpOnly Cookies is recommended as it prevents JavaScript access, enhancing security against XSS attacks.
7. Token Expiry and Security:
Tokens often have an expiration time to enhance security.
8. Including Token in Requests:
For every request to the server, the client sends the token in the Authorization header.
It's a good practice to prefix the token with "Bearer ".
axios.get(URL, {
headers: {
'Authorization': 'Bearer ' + token,
},
})
- Server-Side Validation:
Upon receiving a request, the server retrieves the token.
10. Token Validation and User Authentication:
Using the secret key, the server validates the token and extracts claims from it. If the user information from the claims exists in the server's user table, the server authenticates the user, granting access to requested resources.
Example
Login
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
jwt.sign({ user }, secretKey, { expiresIn: '1h' }, (err, token) => {
if (err) {
res.status(500).send('Error generating token');
} else {
res.json({ token });
}
});
});
Protected route
We are using veriyToken()
function as middleware for every route that needs verification. The request passes through the veriyToken()
and only if the next()
function is called, it passes on to this route and implements the code.
app.get('/dashboard', verifyToken, (req, res) => {
res.send('Welcome to the Home page');
});
// Verify token middleware
function verifyToken(req, res, next) {
const token = req.headers['authorization'];
if (typeof token !== 'undefined') {
jwt.verify(token.split(' ')[1], secretKey, (err, decoded) => {
if (err) {
res.status(403).send('Invalid token');
} else {
req.user = decoded.user;
next();
}
});
} else {
res.status(401).send('Unauthorized');
}
}
Key differences
Storage Location: Sessions are stored on the server, while tokens (JWTs) are stored on the client side.
Stateful vs Stateless: Sessions are stateful, while tokens are stateless, allowing for better scalability in distributed systems.
Expiry Handling: Session expiry is managed by the server, whereas token expiry is handled by the token itself.
Security Measures: JWTs often include digital signatures and support for encryption, enhancing security compared to typical session mechanisms that use cookies, and can be vulnerable to CSRF attacks if not properly protected.
Usage Flexibility: Tokens (JWTs) offer more flexibility in carrying additional information beyond authentication, useful for authorization and custom data transmission.
Which method should be used?
It depends upon the requirement and nature of the application. Most applications use a hybrid approach, token-based authentication for APIs, and session-based authentication for web-based interactions.
I hope you liked this article and if you did don’t forget to give it a like! Which backend language do you use for your projects? 🤔
Comment them down below 👇
Connect with me on-
Posted on December 23, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.