Hello! Welcome back to our course on building production-ready microservices.
In our last lesson, we fortified the "front door" of our system by centralizing JWT validation at the API Gateway. This ensures that only authenticated external users can access our services. However, this raises an important question: what about the communication inside our system? Once a request is past the gateway, should services be able to call each other freely?
In a modern, security-conscious architecture, the answer is no. We operate on a "Zero Trust" principle, meaning we don't implicitly trust any network traffic, even if it originates from within our own cluster. This lesson directly addresses that challenge. Our learning outcome is to compare different strategies for inter-service authentication (e.g., service-to-service JWTs, mTLS). Understanding the trade-offs between these patterns is a hallmark of a senior engineer and a common topic in system design interviews.
Authentication vs. Authorization: A Critical Distinction
Before comparing specific technologies, we must be precise about our terms. It's a distinction that interviewers at top companies will expect you to make clearly.
mTLS vs JWT: What Every Enterprise Developer Should Know
The article "mTLS vs JWT" from Medium offers a sharp clarification of this concept. It sets the foundation for understanding why these two technologies are often used together, not as competitors.
Please read the section "The Authentication vs Authorization Paradigm". Pay close attention to the analogy of the security guard and the access card. This is a powerful way to frame your thinking.
As the article explains:
- Authentication is about verifying identity (AuthN). It answers the question, "Who are you?" In our context, this means
Service-Aproving toService-Bthat it is genuinelyService-A. - Authorization is about verifying permissions (AuthZ). It answers the question, "What are you allowed to do?" This means
Service-Bchecking ifService-Ahas the right to perform a specific action, like reading inventory data.
With this in mind, let's explore the two main strategies for securing service-to-service communication.
Strategy 1: Service-to-Service JWTs (Application Layer)
This approach leverages the OAuth 2.0 framework you're already familiar with, but for machines instead of users. The specific grant type used here is the Client Credentials Grant.
Here's the flow:
- A service (e.g.,
order-service) acts as a "client" and authenticates itself to an authorization server (like Keycloak) using its uniqueclient_idandclient_secret. - The authorization server validates these credentials and issues a short-lived JWT. This token identifies the
order-serviceand may contain claims about its permissions (e.g.,scopes: ["inventory:read", "shipping:create"]). - The
order-servicethen includes this JWT in theAuthorizationheader for all its outgoing requests to other services (e.g.,inventory-service). - The
inventory-service, configured as a resource server, validates the JWT to both authenticate the caller's identity and authorize the requested action based on the token's scopes.
The following video provides a hands-on demonstration of this exact flow using Spring Boot and Keycloak.
Spring Boot 3 Keycloak OAuth 2 Tutorial with Spring Security
The tutorial "Spring Boot 3 Keycloak OAuth 2" by Programming Techie walks through implementing various OAuth 2.0 flows. We will focus on the segments dedicated to the Client Credentials grant, which is designed for machine-to-machine communication.
Please watch the following segments to understand the practical application: Conceptual Overview (51:51 - 54:37): This explains the purpose and simplicity of the Client Credentials flow compared to user-centric flows. Keycloak Configuration (54:37 - 55:57): Observe how a client is configured specifically for this flow. Note the enabling of "Client authentication" and "Service account roles." End-to-End Test (1:03:13 - 1:04:45): This crucial part shows the complete cycle: using Postman to request a token from Keycloak with client credentials, and then using that token to successfully access a secured microservice endpoint.
This pattern is powerful because the JWT can carry rich authorization context. However, it operates at the application layer (L7), meaning your application code is responsible for handling and validating these tokens.
Strategy 2: Mutual TLS (mTLS) (Transport Layer)
Mutual TLS is a more fundamental approach that secures the communication channel itself. You're familiar with standard TLS, which secures your browser's connection to a website (HTTPS). In TLS, your browser (the client) verifies the website's (the server's) certificate.
Mutual TLS (mTLS) extends this by requiring both parties to present and validate each other's certificates. It's a two-way authentication handshake at the transport layer (L4).

The mTLS Handshake
Service-Awants to callService-B. It initiates a connection and presents its X.509 certificate.Service-Bverifies thatService-A's certificate is signed by a trusted Certificate Authority (CA).Service-Bthen presents its own certificate toService-A.Service-AverifiesService-B's certificate against the same trusted CA.- Only after this mutual verification is a secure, encrypted connection established. The application code is unaware this even happened.
The main challenge with mTLS has always been the operational overhead: how do you securely issue, distribute, and rotate certificates for hundreds or thousands of services? This is where a Service Mesh (like Istio or Linkerd) becomes a game-changer.
A service mesh injects a "sidecar" proxy next to each of your microservices. This proxy intercepts all incoming and outgoing traffic. The service mesh's control plane automates the entire certificate lifecycle and enforces that all communication between sidecars uses mTLS.

Test your understanding!
An interviewer asks: "We want to enforce that our payment-service can only be called by the order-service and billing-service. How would you achieve this using mTLS, and how would you achieve it using JWTs?"
Show answer
-
Using mTLS (with a Service Mesh): You would configure a network policy within the service mesh. This policy would state that incoming traffic to the
payment-serviceis only allowed if the mTLS connection originates from a client presenting a certificate with an identity of eitherorder-serviceorbilling-service. This is an infrastructure-level rule that authenticates the caller. -
Using Service-to-Service JWTs: The
payment-servicewould be configured as a resource server. When it receives a request, it would validate the JWT in theAuthorizationheader. It would check theiss(issuer) andsub(subject) claims of the token to identify which service sent the request. It would then check if the subject is in its allowed list (order-service,billing-service). This is an application-level rule that authenticates the caller.
Both achieve the goal, but mTLS does it transparently at the transport layer, while JWT requires application-level logic.
Comparison and The "Defense in Depth" Strategy
So, which one should you choose? For a senior-level interview, the best answer is rarely "one or the other." It's about understanding the trade-offs and how they can work together.
| Feature | Service-to-Service JWTs (Client Credentials) | Mutual TLS (mTLS) |
|---|---|---|
| Primary Purpose | Authentication & Authorization | Strong Authentication |
| OSI Layer | Application Layer (L7) | Transport Layer (L4) |
| Granularity | Fine-grained (scopes, custom claims) | Coarse-grained (service identity) |
| Implementation | In application code (e.g., Spring Security) | In infrastructure (e.g., Service Mesh, Load Balancer) |
| Pros | Carries rich context, flexible, stateless | Very high security, application-agnostic, hard to bypass |
| Cons | Token theft risk, application code responsibility | Doesn't carry authz context, complex without a service mesh |
| "Who are you?" | Yes, based on token claims (sub, iss) | Yes, based on cryptographic certificate identity |
| "What can you do?" | Yes, based on token scopes (scope) | Not directly; only "can you talk to me?" |
The most robust, production-grade architectures use both in a defense in depth model.
mTLS vs JWT: What Every Enterprise Developer Should Know
The article "mTLS vs JWT" concludes by advocating for a layered security model. This is the key takeaway for a production-ready mindset.
Please read the sections "The Enterprise Reality: Use Both" and "The 2026 Recommendation". This synthesizes everything we've discussed into a clear, actionable strategy.
The layered strategy works like this:
- mTLS secures the pipe: The service mesh ensures that
Service-AandService-Bcan only communicate if they have mutually authenticated each other's identity via certificates. This prevents any unauthorized service from even opening a connection. - JWT carries the context: When a user request comes through the API Gateway, the gateway can forward the user's JWT downstream. Even though the service-to-service call is authenticated by mTLS, the business logic inside
Service-Bmight still need to know which user initiated the original request to make fine-grained authorization decisions. The JWT provides this context.
Conclusion
You are now equipped to discuss inter-service authentication strategies with nuance and depth. This is a critical aspect of microservice security that separates junior from senior candidates.
Key Takeaways:
- Inter-service authentication is a cornerstone of a Zero Trust architecture.
- Service-to-Service JWTs (via Client Credentials) are an excellent application-layer pattern for carrying both authentication and authorization context.
- mTLS is a transport-layer pattern that provides strong, infrastructure-level authentication, ensuring only trusted services can communicate.
- The operational complexity of mTLS is largely solved by modern service meshes.
- The most secure approach is "defense in depth": use mTLS to secure the communication channel and pass JWTs to carry user or service-level authorization context for business logic.
Next Up
We've discussed using client secrets for JWTs and private keys for mTLS certificates. A glaring question remains: where do we store these sensitive values? Checking them into Git is a major security vulnerability. In our next lesson, we will tackle this by exploring strategies for secrets management in a microservices environment, looking at tools like HashiCorp Vault and cloud-native solutions.
Can't find a good explanation? Sign up and we'll make it for you
Sign up