DEV Community

Cover image for JWT in Microservices
Daniel Azevedo
Daniel Azevedo

Posted on

JWT in Microservices

Hi devs,

Working with microservices brings a lot of flexibility and scalability to modern applications, but it also introduces new challenges, especially around authentication and authorization. That’s where JSON Web Tokens (JWT) shine.

In this post, I want to break down JWTs in a way that feels practical and relatable, especially for developers diving into microservices. I’ll walk you through what JWTs are, why they’re so valuable, and how you can use them in your own applications—step by step.


What Exactly is a JWT?

If you’ve ever worked on a modern web app or API, chances are you’ve heard about JWTs. But what are they, really?

A JWT (JSON Web Token) is essentially a string of text that securely transmits information (like user data) between systems. The beauty of JWT is that it’s self-contained: everything the system needs to know is inside the token itself.

It’s made up of three parts:

  1. Header: Specifies the token type (JWT) and the signing algorithm (e.g., HS256).
  2. Payload: The actual data—like the user’s ID or role (called claims).
  3. Signature: A cryptographic hash that ensures the token hasn’t been tampered with.

Here’s what a real JWT might look like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Enter fullscreen mode Exit fullscreen mode

At first glance, it’s just a long string. But if you decode it, you’ll see:

  • Header: {"alg": "HS256", "typ": "JWT"}
  • Payload: {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
  • Signature: Ensures this token hasn’t been tampered with.

Why JWTs Matter in Microservices

Microservices thrive on decentralization—and JWTs fit perfectly into this model. Here’s why I think they’re such a great choice:

  1. Stateless Authentication:

    JWTs don’t require a centralized session store. The token itself contains all the necessary data, making it perfect for distributed systems.

  2. Scalability:

    Each service can independently validate a token without having to rely on a separate authentication service every time. This reduces bottlenecks.

  3. Platform Agnostic:

    JWTs are just JSON—they work across languages, frameworks, and platforms.

  4. Security:

    Tokens can be signed and encrypted, protecting both their integrity and contents.


How JWT Works in Practice

Let’s look at a typical workflow:

  1. Authentication:

    The user logs in with their credentials (e.g., username and password). The authentication service validates these credentials and, if valid, generates a JWT.

  2. Token Distribution:

    The token is sent back to the client. The client stores it (often in localStorage or as a cookie) and includes it in the Authorization header of future requests:

   Authorization: Bearer <JWT>
Enter fullscreen mode Exit fullscreen mode
  1. Microservice Validation:

    Each microservice that receives a request with the JWT validates it. If valid, the service processes the request.

  2. Claims-Based Access:

    The microservices use the data inside the JWT (like user roles) to determine what actions the user is allowed to perform.


Hands-On: JWT Implementation in .NET Microservices

Here’s a practical example with three microservices: User, Orders, and Products.

Step 1: Authentication Service

First, let’s generate a JWT when a user logs in.

[HttpPost("login")]  
public IActionResult Login([FromBody] LoginModel model)  
{  
    if (IsValidUser(model))  
    {  
        var token = GenerateJwtToken(model.Username);  
        return Ok(new { Token = token });  
    }  
    return Unauthorized();  
}  

private string GenerateJwtToken(string username)  
{  
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSecretKey"));  
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);  
    var claims = new[]  
    {  
        new Claim(JwtRegisteredClaimNames.Sub, username),  
        new Claim("role", "User")  
    };  

    var token = new JwtSecurityToken(  
        issuer: "YourApp",  
        audience: "YourApp",  
        claims: claims,  
        expires: DateTime.Now.AddMinutes(30),  
        signingCredentials: creds  
    );  

    return new JwtSecurityTokenHandler().WriteToken(token);  
}  
Enter fullscreen mode Exit fullscreen mode

Step 2: Securing Microservices

Now let’s secure the Orders service.

[Authorize]  
[HttpGet("orders")]  
public IActionResult GetOrders()  
{  
    var userId = User.Claims.First(c => c.Type == JwtRegisteredClaimNames.Sub).Value;  
    return Ok($"Orders for user: {userId}");  
}  
Enter fullscreen mode Exit fullscreen mode

Step 3: Validate the Token in Middleware

Add JWT authentication in your service’s Startup.cs:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)  
    .AddJwtBearer(options =>  
    {  
        options.TokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuer = true,  
            ValidateAudience = true,  
            ValidateIssuerSigningKey = true,  
            ValidIssuer = "YourApp",  
            ValidAudience = "YourApp",  
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSecretKey"))  
        };  
    });  
Enter fullscreen mode Exit fullscreen mode

Closing Thoughts

JWTs are a cornerstone of modern microservices, providing a lightweight and scalable way to manage authentication and authorization. They’re not without their challenges (e.g., token expiration management), but their benefits far outweigh the downsides when implemented correctly.

If you’re just starting with microservices, JWT is a great first step toward secure and scalable communication between your services.

Keep coding

Top comments (0)