JWT in Microservices
Daniel Azevedo
Posted on November 24, 2024
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:
-
Header: Specifies the token type (
JWT
) and the signing algorithm (e.g.,HS256
). - Payload: The actual data—like the user’s ID or role (called claims).
- 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
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:
Stateless Authentication:
JWTs don’t require a centralized session store. The token itself contains all the necessary data, making it perfect for distributed systems.Scalability:
Each service can independently validate a token without having to rely on a separate authentication service every time. This reduces bottlenecks.Platform Agnostic:
JWTs are just JSON—they work across languages, frameworks, and platforms.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:
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.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 theAuthorization
header of future requests:
Authorization: Bearer <JWT>
Microservice Validation:
Each microservice that receives a request with the JWT validates it. If valid, the service processes the request.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);
}
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}");
}
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"))
};
});
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
Posted on November 24, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.