Overview

The Partner Portal's IntegrationServiceAPI receives incoming work order messages from a legacy WCF (Windows Communication Foundation) service. This service uses a pre-configured static JWT token for authentication instead of dynamic Azure AD tokens.

Key Characteristics:


Entities Involved

1. WCF Service (External Legacy System)

2. IntegrationServiceAPI

3. Authentication Middleware

4. IncomingTrafficController


Authentication Flow

┌─────────────────────────────────────────────────────────────────┐
│          WCF SERVICE STATIC TOKEN AUTHENTICATION                │
└─────────────────────────────────────────────────────────────────┘

    ┌──────────────────────────────┐
    │  WCF Service                 │
    │  (External legacy system)    │
    └──────┬───────────────────────┘
           │
           │ Has static JWT token
           │ configured in settings
           │
           │ Step 1: Prepare message
           │ - ClientID
           │ - XML Data (byte[])
           │ - MessageType
           ▼
    ┌──────────────────────────────────┐
    │  HTTP Request                    │
    │  POST /api/ReceiveWCFIncoming... │
    │  Authorization: Bearer eyJ0eX... │
    │  Body: IncomingMessageRequest    │
    └──────┬───────────────────────────┘
           │
           │ Step 2: Request arrives
           ▼
    ┌──────────────────────────────────┐
    │  IntegrationServiceAPI           │
    │  Multi-Scheme Authenticator      │
    └──────┬───────────────────────────┘
           │
           │ Step 3: Read token & route
           │ Parse JWT token:
           │ - Issuer: "PartnerPortal"?
           │ - Claim: service_name="WCFservice"?
           │ - Path: /api/ReceiveWCFIncoming...?
           │
           ├─── All Valid ───┐   Invalid ────┐
           │                 │                 │
           ▼                 ▼                 ▼
    ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
    │  Route to    │  │  Validate    │  │  401         │
    │  StaticToken │  │  Token       │  │  Unauthorized│
    │  Scheme      │  │              │  │              │
    └──────────────┘  └──────┬───────┘  └──────────────┘
                             │
                             │ Step 4: Token validation
                             │ - Signature (HS256 symmetric key)
                             │ - Issuer = "PartnerPortal"
                             │ - Audience = "EGU.PartnerPortal"
                             │ - Lifetime (if expiration set)
                             │
                             ├─── Valid ────┐
                             │              │
                             ▼              ▼
                      ┌──────────────┐  ┌──────────────┐
                      │  Forward to  │  │  200 OK      │
                      │  Controller  │  │              │
                      └──────┬───────┘  └──────────────┘
                             │
                             │ Step 5: Process message
                             ▼
                      ┌──────────────────────┐
                      │  IncomingTraffic     │
                      │  Controller          │
                      └──────┬───────────────┘
                             │
                             │ Step 6: Decode & validate XML
                             │ Step 7: Call ApiService
                             │ Step 8: Return response
                             ▼
                      ┌──────────────────────┐
                      │  Success response    │
                      │  sent to WCF         │
                      └──────────────────────┘

Static JWT Token

Token Format

The static JWT token is a standard JSON Web Token with three parts:

Header:

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload (Claims):

{
  "iss": "PartnerPortal",
  "aud": "EGU.PartnerPortal",
  "service_name": "WCFservice",
  "exp": 1893456000,
  "iat": 1733456000
}

Signature:

Required Claims

||Claim||Type||Value||Description|| |iss|String|"PartnerPortal"|Issuer - identifies token source| |aud|String|"EGU.PartnerPortal"|Audience - identifies intended recipient| |service_name|String|"WCFservice"|Custom claim identifying WCF service| |exp|Numeric|Unix timestamp|Expiration time (optional but recommended)| |iat|Numeric|Unix timestamp|Issued at time (optional)|

Token Generation (WCF Side)

The WCF service must generate the JWT token using the shared secret key:

// Pseudocode - WCF service implementation
var secretKey = "<base64-encoded-secret-key>";
var signingKey = new SymmetricSecurityKey(Convert.FromBase64String(secretKey));
var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

var claims = new[]
{
    new Claim("iss", "PartnerPortal"),
    new Claim("aud", "EGU.PartnerPortal"),
    new Claim("service_name", "WCFservice")
};

var token = new JwtSecurityToken(
    issuer: "PartnerPortal",
    audience: "EGU.PartnerPortal",
    claims: claims,
    expires: DateTime.UtcNow.AddYears(10), // Long-lived token
    signingCredentials: credentials
);

var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
// Store tokenString in Azure environment variable

IntegrationServiceAPI Configuration

Required Settings

File: appsettings.json

{
  "AccessToken": {
    "SecretKey": "<base64-encoded-secret-key>"
  }
}

Secret Key:

Authentication Configuration

Location: IntegrationServiceAPI/Services/Middleware/AuthenticationConfiguration.cs:148-177

The middleware configures three authentication schemes:

  1. AzureAdScheme - For Azure AD user tokens (Swagger)
  2. CiamScheme - For CIAM user tokens (not currently used)
  3. StaticTokenScheme - For WCF service static tokens

StaticTokenScheme Configuration:

.AddJwtBearer(AuthenticationConstants.StaticTokenScheme, opts =>
{
    var secretKey = configuration["AccessToken:SecretKey"]?.Trim().TrimEnd(',');
    var signingKey = new SymmetricSecurityKey(Convert.FromBase64String(secretKey));

    opts.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = "PartnerPortal",
        ValidateAudience = true,
        ValidAudience = "EGU.PartnerPortal",
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = signingKey,
        ClockSkew = TimeSpan.FromMinutes(5)
    };
});

Endpoint Restrictions

Allowed Endpoint

Static tokens are ONLY valid for this endpoint:

Enforcement Logic:

private static readonly string[] AllowedWcfEndpoints = new[]
{
    "/api/ReceiveWCFIncomingMessage"
};

private static bool IsAllowedWcfEndpoint(PathString requestPath)
{
    return AllowedWcfEndpoints.Any(endpoint =>
        requestPath.StartsWithSegments(endpoint, StringComparison.OrdinalIgnoreCase));
}

Path Validation Flow:

  1. Token parsed and identified as static token (issuer + service_name claim)
  2. Request path checked against allowed endpoints
  3. If path matches → Route to StaticTokenScheme
  4. If path doesn't match → Reject with 401 Unauthorized

Security Benefit:


Step-by-Step Authentication Process

Step 1: WCF Service Prepares Request

What happens:

Who's involved:

Result:


Step 2: Request Arrives at IntegrationServiceAPI

What happens:

Who's involved:

Result:


Step 3: Token Routing Decision

What happens:

Who's involved:

Result:


Step 4: Token Validation

What happens:

Who's involved:

What's validated:

Result:


Step 5: Controller Processes Message

What happens:

Who's involved:

Result:


Step 6: Response Returned

What happens:

Who's involved:

Result: