DEV Community

Vishal Yadav
Vishal Yadav

Posted on

Understanding JWT Authentication: A Comprehensive Guide with Examples

In the world of web development, security is paramount. One of the most popular methods for securing web applications is JSON Web Token (JWT) authentication. In this comprehensive guide, we'll explore what JWT authentication is, how it works, and how you can implement it in your web applications, with practical examples.

What is JWT Authentication?

JWT authentication is a method of securely transmitting information between parties as a JSON object. It's commonly used for authenticating users and transmitting data securely between a client and a server.

How Does JWT Authentication Work?

JWT authentication works by creating a token that contains encoded information about a user or session. This token is then sent from the client to the server with each request, allowing the server to verify the authenticity of the request and grant access accordingly.

Here's a simplified overview of the JWT authentication process:

  1. User Authentication: When a user logs in to a web application, the server verifies their credentials (e.g., username and password).
  2. Token Generation: Upon successful authentication, the server generates a JWT containing relevant information (e.g., user ID, expiration time) and signs it using a secret key.
  3. Token Transmission: The JWT is sent back to the client and stored (typically in local storage or cookies) for future use.
  4. Request Authorization: With each subsequent request, the client includes the JWT in the request headers.
  5. Token Verification: The server verifies the JWT's signature and decodes its contents to authenticate the user and determine their access rights.
  6. Response Handling: Based on the JWT's validity and the user's permissions, the server processes the request and sends an appropriate response.

Key Components of JWT

  • Header: Contains metadata about the token, such as the type of token and the hashing algorithm used.
  • Payload: Contains the actual data being transmitted, such as user information or permissions.
  • Signature: Ensures the integrity of the token by combining the header, payload, and a secret key.

Benefits of JWT Authentication

  • Statelessness: JWTs are self-contained and do not require server-side storage of session data, making them ideal for stateless architectures.
  • Scalability: Since JWTs do not rely on server-side storage, they can easily scale to accommodate high volumes of users.
  • Security: JWTs are digitally signed, providing a secure means of transmitting data between parties.

Implementing JWT Authentication: Example with Node.js and Express

Let's look at a simple example of implementing JWT authentication in a Node.js and Express application.

// Required Libraries
const express = require('express');
const jwt = require('jsonwebtoken');

// Create Express App
const app = express();

// Secret Key for JWT Signing
const secretKey = 'your-secret-key';

// Mock User Database
const users = [
  { id: 1, username: 'user1', password: 'password1' },
  { id: 2, username: 'user2', password: 'password2' },
];

// Route to Authenticate User and Generate JWT
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username && u.password === password);

  if (user) {
    // Generate JWT with user ID
    const token = jwt.sign({ userId: user.id }, secretKey);
    res.json({ token });
  } else {
    res.status(401).json({ message: 'Invalid credentials' });
  }
});

// Middleware to Authenticate Requests
const authenticateToken = (req, res, next) => {
  const token = req.headers['authorization'];
  if (!token) return res.status(401).json({ message: 'Unauthorized' });

  jwt.verify(token, secretKey, (err, user) => {
    if (err) return res.status(403).json({ message: 'Invalid token' });
    req.user = user;
    next();
  });
};

// Protected Route
app.get('/protected', authenticateToken, (req, res) => {
  res.json({ message: 'Protected route accessed successfully' });
});

// Start Server
app.listen(3000, () => {
  console.log('Server running on port 3000');
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

JWT authentication is a powerful and widely-used method for securing web applications. By understanding how JWTs work and following best practices for implementation, you can enhance the security and reliability of your web applications. Whether you're building a simple blog or a complex enterprise application, JWT authentication provides a flexible and scalable solution for protecting your users' data and ensuring a seamless user experience.

Top comments (28)

Collapse
 
kevinduffey profile image
kevinduffey

Good primer but a bit was left out that would probably be helpful for someone thinking about JWT vs say, OAUTH2 or an API token. In particular I'd add that first, you should NEVER store JWT tokens in local storage. The server should always use httpOnly flag, and it should only be done over SSL/TLS. "But then the client cant read the token data and get info like user id, name, etc from the token". Yup. That info should be returned as part of the body response on login when the token is also returned. Any details like user name, email, etc that need to be used in the app, should only come back on login as the response body. This ensures that nobody on the client or in between client and server (say.. an extension for example ) can access the token and use it for nefarious purposes.

The second thing I'd add is that you almost always want a refresh token AND an access token generated. The refresh token is long lived.. maybe 30 days, or just 1 day, if your domain requires daily logins. The access token is short lived. I'd argue 30 minutes max, but I typically have mine at 5 minutes. The access token contains the details like RBAC, etc.. that the server side uses to determine if the request being made is allowed. It is also used to enable invalidation of a user. For example, a user is an employee.. who got fired but had logged in 1 minute prior. Well now they are angry and they can wreak havoc for as long as that access token allows them to (assuming their "role" in the token allows them to do nefarious things). But HR invalidates their user account. When the access token expires in a few minutes.. the refresh token is used to look up their user account (e.g. similar to a login) but perhaps its in a Redis table or some other manner in which a user account is used. The point is, at that point the account is discovered to be disabled, so the refresh token is now invalidated and a 401 is returned. The client side will then redirect to a login page again, and when they try to log in.. no longer can do so. This method avoids having to have some sort of server side Redis blacklist DB to keep track of all users, etc.

Collapse
 
sillydeveloper profile image
Vitor Leitão

If it's properly done, implementing JWT is not hard.
What might be worth mentioning is that besides validating if a token is right and valid, you should have a system to be able to deactivate tokens.

Collapse
 
ariffazmi profile image
Ariff Azmi

You can implement this by using redis. Set the ttl of the token in redis. After that, before the server verify the token, you must check the token if exist in the redis, then proceed to the token validation.

Collapse
 
instalab profile image
Samuel Boczek

Annnd, bravo for reinventing sessions.

Collapse
 
anna_latukhova_d87446e5ec profile image
Anna Latukhova

Exactly!

Collapse
 
vyan profile image
Vishal Yadav

Yes!

Collapse
 
szalonna profile image
Joe

In my experience JWT works fine in a close, trusted system where a token could live like only for a few seconds or even minutes and each node is able to verify the tokens validity by checking the signature and using only the permissions defined in the token.
For a client-server connection where the client is outside of this trusted system (e.g. a mobile app, a browser) there should be a session-based authorization. A session can store a refresh token on the server side and each request from the client should go through an API gateway or whatever you call, which checks the session's validity and asks for a short lived access token with the refresh token and forwards the request with the token to the proper service.

The benefit of this combination is that the app can control the active sessions (e.g. you can list your logged in devices, geolocation in Google Accounts and even destroy a session if you want without even touching the device itself), you can control the length of a session independently of the refresh/access token's lifespan, you can use short lived access tokens which can be verified by the services.

If you put the token to a HTTP-only cookie, you basically use the token as a session ID, but without the benefits of a session. Yes, you can blacklist a token, but in this case your service nodes have to call back to the auth service to check if it is blacklisted or not.

Collapse
 
bytenaija profile image
Everistus Olumese

JWT coupled with Zero Trust Access developers.cloudflare.com/cloudfla... is the way forward.

Collapse
 
yoshida_daisuke_6869c822f profile image
Yoshida Daisuke

Thanks

Collapse
 
vyan profile image
Vishal Yadav

Thanks!

Collapse
 
rishadomar profile image
Rishad Omar

Well explained thank you. My understanding is that today I should not be implementing my own authentication system. For example I would use AWS Cognito. I'm guessing what you've described is what is done in Cognito too. I would be interested in exploring further. JWT renewals. How to store on client. And how services like Cognito use it.

Collapse
 
vyan profile image
Vishal Yadav

Thanks!

Collapse
 
ozzythegiant profile image
Oziel Perez

I disagree with this approach to JWT because the token is not secure and hidden from JS. The way I do it is to store it in an httponly cookie so that nothing can touch it. You will still need to persist some data to determine if a person is logged in but I think that should be just user ID and user's role. Authorization would just happen server side with the JWT from the cookie; the persisted data on the front end would just be to restrict views

Collapse
 
coelhoadler profile image
Adler Coelho Santos

Congratulations, great article! I have one doubt: What is the best way to store a JWT in Client Side?

Collapse
 
vyan profile image
Vishal Yadav

You can prefer to use cookie and set credentials via Cookie on browser.

Collapse
 
instalab profile image
Samuel Boczek • Edited

Failed to mention that JWT tokens are only secure as long as you can invalidate them, but if you have to invalidate them then you need some database to store tokens in, which renders JWT pointless for many practical applications.

Long lived JWT - need to store information about invalidated tokens === basically the same as sessions but overly complicated for the purpose.

Short lived JWT - only useful to closed networks, e.g. servers talking to each other. For frontend, do you want to logout users every 5 seconds?

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more