Feb 21, 2026

Service-to-Service Identity & Authorization Strategy

This document outlines the architecture for Service A to securely communicate with downstream services (Svc B, C, D) while preserving the original human user's identity and permissions. We are prioritizing a "Passport Pattern" (Token Forwarding) to ensure zero-trust security across our microservices mesh.


Recommended Approach: Unified Identity Propagation
In this model, Service A acts as a "delivery agent." It receives the user's "Passport" (Okta Access Token) and forwards it directly to downstream services.
How it Works:
  1. User Login: The user logs into Svc A via the authorization_code flow. Okta issues an Access Token.
  2. The "Messy" Token: We use the existing Okta Group Claim that includes all groups (Finance, Claims, etc.). This ensures the token is a complete "Permission Slip."
  3. App Logic (Svc A): Svc A inspects the token. If it sees the user belongs to Group_SvcB, it proceeds with the call.
  4. Token Forwarding: Svc A calls Svc B and passes the exact same User Access Token in the Authorization: Bearer header.
  5. Downstream Validation (Svc B/C/D): Svc B validates the Okta signature and checks the groups array for its specific required group.
Pros:
  • Full User Context: Svc B knows exactly which human is making the request (critical for auditing).
  • Decoupled Logic: Authorization logic lives in the service code, allowing for rapid changes without infrastructure deployments.
Cons:
  • Token Size: Tokens can become large if a user belongs to many groups.
  • Data Leakage: Svc A sees all of a user's groups, even those unrelated to Svc A's function.

Alternative 1: Scoped Filtered Claims ("The Tight Way")
If security requirements demand that Svc A only sees the groups it absolutely needs, we use Regex-filtered claims.
How it Works:
We create a custom claim (e.g., svc_permissions) in the Okta Authorization Server. We use a Regex (e.g., .*svcb.*|.*svcc.*) to strip away all "Sandbox" and "Portal" groups, leaving only a clean list for the app.
Comparison:
FeatureRecommended (Full Groups)Alternative (Filtered Claim)
Okta EffortNone (Use existing)High (Requires TF/UI updates)
App EffortSift through all groupsRead clean list
SecurityBroad visibilityPrinciple of Least Privilege

Alternative 2: Multiple Priority Rules
We could create separate Okta Policy Rules for every service (e.g., a "Service B Rule" and a "Service C Rule").
Why we are NOT doing this (The "Complexity Trap"):
Using multiple priority-based rules creates a Maintenance Nightmare for the following reasons:
  1. First-Match Logic: Okta stops evaluating rules at the first match. If a user is in Group B AND Group C, and Rule B has higher priority, the user will never get the permissions for Service C.
  2. Permutation Explosion: To fix the first-match issue, you would have to create rules for every possible combination (e.g., a "B+C Rule," a "B+D Rule," an "All Access Rule").
  3. Brittle Infrastructure: Adding a single new service would require re-calculating the priority of every existing rule in the system.

Implementation Checklist
  • Okta: Ensure the groups claim is included in the Access Token (not just the ID Token).
  • Svc A: Configure OIDC to request the necessary scopes (openidprofile, etc.).
  • Common Library: Implement a standard is_authorized(token, required_group) helper function for all services.
  • Middleware: Ensure Svc B, C, and D are configured to validate JWT signatures against the Okta discovery endpoint.