Home/Learn/Microservices/Service-to-Service Authentication

Service-to-Service Authentication

Advanced
Security

Mutual TLS or short-lived JWT access tokens (client credentials flow) authenticate services with each other; avoid embedding long-lived secrets in code.

Overview

Service-to-service authentication solves the "how does service A prove its identity to service B?" problem. Two dominant approaches: mTLS (mutual TLS) where each service presents a client certificate, and the OAuth2 Client Credentials Flow where a service exchanges its client_id + client_secret for a short-lived JWT access token from an identity provider (Keycloak, Okta, AWS Cognito). mTLS is powerful but operationally complex (certificate rotation, PKI management); a service mesh (Istio) automates it transparently via SPIFFE/SPIRE identity. Client Credentials is simpler — the receiving service just validates the JWT signature with a public JWKS endpoint — but requires all services to have access to an auth server. In both cases, never embed long-lived shared secrets (API keys) in code or environment variables.

OAuth2 Client Credentials with Spring Security

The calling service obtains a token from an identity provider using its client ID and secret. Spring Security's OAuth2 client support automates token acquisition and refresh.

Properties + Java — OAuth2 client credentials flow
# application.properties — order-service calling payment-service
spring.security.oauth2.client.registration.payment-service.client-id=order-service
spring.security.oauth2.client.registration.payment-service.client-secret=${CLIENT_SECRET}
spring.security.oauth2.client.registration.payment-service.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.payment-service.scope=payments:create
spring.security.oauth2.client.provider.keycloak.token-uri=  https://keycloak.internal/realms/platform/protocol/openid-connect/token

# Configure WebClient with OAuth2 token auto-injection
@Configuration
public class WebClientConfig {
    @Bean
    public WebClient paymentWebClient(
            OAuth2AuthorizedClientManager clientManager) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
            new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientManager);
        oauth2.setDefaultClientRegistrationId("payment-service");

        return WebClient.builder()
            .baseUrl("https://payment-service.internal")
            .filter(oauth2)  // automatically attaches Bearer token
            .build();
    }
}

Validating incoming service tokens (resource server)

The receiving service (payment-service) configures Spring Security as a resource server. It validates the JWT signature using the JWKS URI from the identity provider — no shared secret needed.

Java — Spring resource server JWT validation
# payment-service application.properties
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=  https://keycloak.internal/realms/platform/protocol/openid-connect/certs

@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/payments/**").hasAuthority("SCOPE_payments:create")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt.jwtAuthenticationConverter(
                    jwtAuthenticationConverter()))
            );
        return http.build();
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter conv = new JwtGrantedAuthoritiesConverter();
        conv.setAuthorityPrefix("SCOPE_");
        conv.setAuthoritiesClaimName("scope");
        JwtAuthenticationConverter jwtConv = new JwtAuthenticationConverter();
        jwtConv.setJwtGrantedAuthoritiesConverter(conv);
        return jwtConv;
    }
}

mTLS with Istio service mesh

Istio automates mTLS between all pods using SPIFFE SVIDs (X.509 certificates). PeerAuthentication enforces strict mTLS mode; no application code changes are needed.

YAML — Istio PeerAuthentication + AuthorizationPolicy
# PeerAuthentication — enforce strict mTLS in the namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT    # reject all non-mTLS traffic

# AuthorizationPolicy — payment-service only accepts calls from order-service
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payment-service-authz
  namespace: production
spec:
  selector:
    matchLabels:
      app: payment-service
  rules:
    - from:
        - source:
            # Only order-service service account can call payment-service
            principals:
              - "cluster.local/ns/production/sa/order-service"
      to:
        - operation:
            methods: ["POST"]
            paths: ["/payments/*"]

Key Points to Remember

  • 1Never use long-lived shared API keys between services — use short-lived tokens (15min–1h) or mTLS certificates.
  • 2Client Credentials flow: service obtains a token from the auth server, attaches it as Bearer in every request.
  • 3Spring Security resource server validates JWT signature via JWKS URI — no shared secret, no round-trip to auth server per request.
  • 4mTLS via Istio is transparent to application code — Envoy sidecar handles TLS handshake and certificate rotation.
  • 5Inject client_secret via environment variable or Vault — never hardcode in application.properties or source code.
  • 6Use scopes to limit what each service is permitted to do — payments:read vs payments:create as separate scopes.

Interview Questions

Sign in to ask Aria
1

What is the OAuth2 Client Credentials flow and how does it differ from Authorization Code flow?

EasyAmazon
2

How does a resource server validate a JWT without calling the identity provider on every request?

MediumNetflix
3

What is mTLS and how does Istio automate certificate rotation for service-to-service mTLS?

HardGoogle
4

How would you revoke a compromised service identity in an mTLS setup?

HardUber
5

Compare mTLS and OAuth2 client credentials for service-to-service auth — when would you choose each?

MediumMeta

Ask Aria about Service-to-Service Authentication

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…