Step-by-Step Process & Entities


Entities Involved

1. ApiService

2. ServiceTokenHandler (Middleware)

3. Microsoft Entra ID (Azure AD Tenant)

4. IntegrationServiceAPI



High-Level Authentication Flow

┌─────────────────────────────────────────────────────────────────┐
│       SERVICE-TO-SERVICE AUTHENTICATION FLOW                    │
└─────────────────────────────────────────────────────────────────┘

    ┌──────────────────┐
    │   ApiService     │
    │   (Needs to call │
    │   Integration)   │
    └────────┬─────────┘
             │
             │ Step 1: Make API call
             │ (e.g., send XML message)
             ▼
    ┌──────────────────────────┐
    │  ServiceTokenHandler     │
    │  (Middleware)            │
    └────────┬─────────────────┘
             │
             │ Step 2: Need token first!
             │ Request token from Entra ID
             │ Sends:
             │  - Client ID (stored as env. variable in container app)
             │  - Client Secret (stored as env. variable in container app)
             │  - Scope
             ▼
    ┌──────────────────────────────┐
    │  Microsoft Entra ID          │
    │  Token Endpoint              │
    └────────┬─────────────────────┘
             │
             │ Step 3: Entra ID validates
             │  ✓ Client ID exists
             │  ✓ Client secret matches
             │  ✓ Service has permission
             ▼
    ┌──────────────────────────────┐
    │  Entra ID Returns Token      │
    │  (for IntegrationServiceAPI) │
    └────────┬─────────────────────┘
             │
             │ Step 4: Token attached to request
             │ Authorization: Bearer eyJ...
             ▼
    ┌──────────────────────────────┐
    │  IntegrationServiceAPI       │
    │  Validates Token             │
    └────────┬─────────────────────┘
             │
             │ Step 5: Token validation
             │  ✓ Signature valid
             │  ✓ Issuer correct
             │  ✓ Audience correct
             │  ✓ Not expired
             ▼
    ┌──────────────────────────────┐
    │  ✅ Process Request           │
    │  Execute API logic           │
    │  Return Response             │
    └──────────────────────────────┘


Bidirectional Communication

Both Services Call Each Other

The authentication works in both directions:

Direction 1: ApiService → IntegrationServiceAPI

Direction 2: IntegrationServiceAPI → ApiService

Same Process, Different Credentials

The authentication flow is identical in both directions:

Only the credentials differ:

DirectionClient ID (Who's calling)Client Secret (Who's calling)Audience (Who's being called)
ApiService → IntegrationApiService IDApiService secretIntegrationServiceAPI ID
Integration → ApiServiceIntegrationServiceAPI IDIntegrationServiceAPI secretApiService ID



Step-by-Step Authentication Process

Note: The steps below show ApiService calling IntegrationServiceAPI, but the process is identical in reverse (IntegrationServiceAPI calling ApiService) - just swap the service names and credentials.

Step 1: ApiService Needs to Call IntegrationServiceAPI

What happens:

Who's involved:

Result:


Step 2: ServiceTokenHandler Requests Token

What happens:

Who's involved:

What's sent to Entra ID:

Result:


Step 3: Entra ID Validates Client Credentials

What happens:

Who's involved:

What Entra ID checks:

Result:


Step 4: Entra ID Issues Access Token

What happens:

Who's involved:

What's in the token:

Result:


Step 5: Token Attached to Request

What happens:

Who's involved:

Result:


Step 6: IntegrationServiceAPI Validates Token

What happens:

Who's involved:

What's validated:

Result:


Step 7: API Processes Request

What happens:

Who's involved:

Result:


Token Caching & Reuse

Token Caching

ServiceTokenHandler caches tokens to improve performance:

First request:

  1. No cached token available
  2. Request token from Entra ID (takes ~100-200ms)
  3. Cache token for 1 hour
  4. Use token for request

Subsequent requests (within 1 hour):

  1. Check cache for valid token
  2. Use cached token (takes ~1-5ms)
  3. No Azure AD call needed

After 1 hour:

  1. Cached token expired
  2. Request new token from Entra ID
  3. Update cache with new token



Configuration

ApiService Configuration

What's needed:

SettingDescriptionExample Value
Client IDApiService's application ID4dad5d62-dc8c-4378-8bd0-ae736a4d73fe
Client SecretApiService's secret keyabc123~XYZ789-VerySecret
Tenant IDAzure AD tenant6073ce8b-73f3-4df4-9b80-5e40cdc6965f
ScopeIntegrationServiceAPI scopeapi://bd5100ee-af63-4880-8c60-47d4207d60c1/.default

Where configured:


IntegrationServiceAPI Configuration

What's needed:

SettingDescriptionExample Value
Client IDIntegrationServiceAPI's IDbd5100ee-af63-4880-8c60-47d4207d60c1
Client SecretIntegrationServiceAPI's secret keyxyz789~ABC123-VerySecret
Tenant IDAzure AD tenant6073ce8b-73f3-4df4-9b80-5e40cdc6965f
ScopeApiService scopeapi://4dad5d62-dc8c-4378-8bd0-ae736a4d73fe/.default

Where configured:


Quick Reference

ApiService

PropertyValue
Client ID4dad5d62-dc8c-4378-8bd0-ae736a4d73fe
Needs Client Secret✅ Yes (calls IntegrationServiceAPI and validates tokens)
Tenant ID6073ce8b-73f3-4df4-9b80-5e40cdc6965f

IntegrationServiceAPI

PropertyValue
Client IDbd5100ee-af63-4880-8c60-47d4207d60c1
Needs Client Secret✅ Yes (calls ApiService and validates tokens)
Tenant ID6073ce8b-73f3-4df4-9b80-5e40cdc6965f