Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • HTTP message handler that intercepts outgoing requests
  • Location: Source/EGU.PartnerPortal.ApiService/Middleware/Handler/ServiceTokenHandler.cs
  • Automatically gets tokens from Azure ADEntra ID
  • Attaches tokens to requests going to IntegrationServiceAPI

3. Microsoft Entra ID (Azure AD Tenant)

...

┌─────────────────────────────────────────────────────────────────┐
│       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 AzureEntra ADID
             │ 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             │
    └──────────────────────────────┘

...

  • ServiceTokenHandler checks if it has a valid cached token
  • If no valid token, requests new one from Azure ADEntra ID
  • Sends client credentials to Azure AD Entra ID token endpoint

Who's involved:

  • ServiceTokenHandler
  • Microsoft Entra ID

What's sent to Azure ADEntra ID:

  • Client ID: ApiService's application ID (stored as env variable in container app)
  • Client Secret: ApiService's secret key (stored securelyas env variable in container app)
  • Scope: .default (all permissions the app has)
  • Grant Type: client_credentials

...

  • Request sent to Azure AD for authentication

...

Step 3:

...

Entra ID Validates Client Credentials

What happens:

  • Azure AD Entra ID receives the token request
  • Validates the client ID exists in the tenant
  • Validates the client secret matches what's registered
  • Checks if the app has permission to access IntegrationServiceAPI

Who's involved:

  • Microsoft Entra ID

What Azure AD Entra ID checks:

  • ✅ Does this client ID exist?
  • ✅ Does the client secret match?
  • ✅ Does this app have permission to call IntegrationServiceAPI?

...

  • If all valid → Proceed to Step 4
  • If any invalid → Return error (401 Unauthorized)

...

Step 4:

...

Entra ID Issues Access Token

What happens:

  • Azure AD Entra ID generates an access token
  • Token valid for 1 hour
  • Token contains app identity (not user identity)
  • Token returned to ServiceTokenHandler

...

  • IntegrationServiceAPI receives request with token
  • Authentication middleware examines the token
  • Validates token is authentic and valid (using cached Azure AD Entra ID public keys - no Azure AD Entra ID call needed)

Who's involved:

  • IntegrationServiceAPI
  • JWT Authentication Middleware
  • Azure AD Entra ID public keys (cached locally, refreshed every 30 minutes)

...

  • Signature: Proves token came from Azure ADEntra ID
  • Issuer: Confirms it's from the correct Azure AD Entra ID tenant
  • Audience: Ensures it's for IntegrationServiceAPI
  • Expiration: Checks it hasn't expired (1-hour lifetime)
  • App Permissions: Verifies ApiService has permission

...

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

...

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

Benefits:

  • ⚡ Fast (no Azure AD call for most requests)
  • 📈 Scalable (no rate limits on cached tokens)
  • 🔒 Secure (token automatically refreshed)

Security Details

Client Secret

What it is:

  • A secret key that proves ApiService's identity
  • Like a password for the application (not a user)
  • Created in Azure AD app registration
  • Must be kept secure

Where it's stored:

  • Development: User secrets or secrets.json
  • Production: Use environment variables (or in Key Vault)
  • Never: Committed to source control

How it's used:

  • ServiceTokenHandler reads it from configuration
  • Sends it to Azure AD with client ID
  • Azure AD validates it matches the registered secret
  • If valid, token is issued

Security best practices:

  • ✅ Use environment variables (or in Key Vault)
  • ✅ Rotate periodically (every 6-12 months)
  • ❌ Never commit to git
  • ❌ Never hardcode in source files

Token Validation

How IntegrationServiceAPI validates tokens:

  1. Signature Validation

    • Uses Azure AD's public keys
    • Proves token was issued by Azure AD
    • Prevents forged tokens
  2. Issuer Validation

    Checks
  3. token
  4. came from correct Azure AD tenant
  5. Prevents tokens from other organizations
  6. Audience Validation

    • Ensures token is for IntegrationServiceAPI
    • Prevents token reuse across different APIs
  7. Expiration Validation

    • Checks token hasn't expired (1 hour)
    • Includes 5-minute clock skew tolerance
  8. Permission Validation

    • Checks ApiService has required permissions
    • Based on Azure AD app role assignments


...

Configuration

ApiService Configuration

...

Where configured:

  • Environment variables (recommendedin apiservice container app)
  • appsettings.json (development only, with secrets.json)

...

Where configured:

  • Environment variables (recommendedin integrationservice container app)
  • appsettings.json (development only, with secrets.json)

...