Inter-service Communication

Details on Feign, OAuth2, and Kafka event flows between Arya Banking services.

Communication Strategies

Arya Banking utilizes three primary communication patterns to ensure scalability, security, and loose coupling.


1. Synchronous Feign (REST)

Internal service-to-service calls are handled by OpenFeign. To secure these calls, we use the OAuth2 Client Credentials grant.

Machine-to-Machine (M2M) Flow

  1. Source Service (e.g., Auth Service) triggers a Feign call.
  2. OAuth2 Interceptor requests a machine-to-machine JWT from Keycloak using its own client-id and client-secret.
  3. Keycloak returns a JWT with ROLE_INTERNAL_SERVICE.
  4. Source Service injects Authorization: Bearer <JWT> into the outgoing request.
  5. Target Service (e.g., User Service) validates the JWT and verifies the role.

Implementation Pattern

> Java code-highlight
// OAuth2FeignConfig (Common Library pattern)
@Bean
public RequestInterceptor oauth2RequestInterceptor() {
    return requestTemplate -> {
        OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest
            .withClientRegistrationId(clientRegistrationId).build();
        OAuth2AuthorizedClient client = authorizedClientManager.authorize(request);
        requestTemplate.header("Authorization", "Bearer " + client.getAccessToken().getTokenValue());
    };
}

2. API Flow Deep-Dive

User Registration Sync

When a user registers, the flow spans two services:

0/0

Account Locking (Login Failures)

When login fails multiple times, the Auth Service signals the User Service:

0/0

3. Asynchronous Events (Kafka) — UPDATED

State changes are propagated asynchronously using Apache Kafka and Avro Schemas.

Event Topics & Producers/Consumers

TopicSchemaProducerConsumers
user.create.eventUserCreateEventAuth Service (UserEventProducer)Auth Service (UserUpdateEventListener)
user.update.eventOutboxKafkaEvent (wrapping UserCreateEvent)User Service (outbox relay)Auth Service
auth.failed.eventLoginFailedEventAuth Service (UserEventProducer)User Service (UserEventListeners)

Producer: Auth Service User Registration

0/0

Producer: Auth Service Login Failure

0/0

Producer Logic (UserEventProducer in Auth Service)

The UserEventProducer in the Auth Service uses a typed KafkaTemplate<String, LoginFailedEvent> to send Avro-encoded records:

> Java code-highlight
// Auth Service - UserEventProducer
kafkaTemplate.send(AUTH_FAILED_TOPIC, event.getUserId().toString(), event);

Consumer Logic (UserUpdateEventListener in Auth Service)

> Java code-highlight
// Auth Service - UserUpdateEventListener
@KafkaListener(id = "user-update-event", topics = USER_UPDATE_TOPIC)
public void onUserUpdateEvent(OutboxKafkaEvent event) {
    UserCreateEvent userCreateEvent = GsonParser.fromJson(
        event.getPayload().toString(), UserCreateEvent.class);
    keyCloakService.onUserUpdateEvent(userCreateEvent);
}

Consumer Logic (UserEventListeners in User Service)

> Java code-highlight
// User Service - UserEventListeners
@KafkaListener(id = "login-failed-event", topics = AUTH_FAILED_TOPIC)
public void onUserUpdateEvent(LoginFailedEvent event) {
    EventContext.setEventContext(
        event.getMetadata().getCorrelationId().toString(),
        event.getMetadata().getEventId().toString()
    );
    UpdateSecurityDetailsDto dto = new UpdateSecurityDetailsDto(null, event.getIsLockUser());
    securityDetailsService.updateSecurityCredentials(
        event.getUserId().toString().toUpperCase(), dto);
}

4. Port & Path Mapping Reference

SourceDestinationPathPurpose
User ServiceAuth Service/internal/api/auth/register/usersSync registration to Keycloak
Auth ServiceUser Service/internal/api/security-details/{id}Track login failures (legacy Feign)
Auth ServiceUser ServiceKafka auth.failed.eventTrack login failures (event-driven)
User ServiceAuth ServiceKafka user.update.eventUser lifecycle events (outbox)
Auth ServiceKeycloak/admin/realms/{realm}/rolesProvision RBAC roles
Admin ServiceKeycloak/admin/realms/{realm}/rolesProvision RBAC roles
Admin ServiceVault/v1/auth/approle/roleProvision service secrets

Internal endpoints (marked with /internal/) are protected by ROLE_INTERNAL_SERVICE and are not accessible through the API Gateway by default.