Docs/Identity/JWT & Security Context

JWT & Security Context

How JWT tokens from your identity provider are converted into MACAW security contexts. This conversion is the foundation of user-specific policy enforcement.

JWT to Security Context Conversion

When your application passes a JWT token, the Identity Bridge extracts claims and maps them to MACAW's hierarchical security context:

Input: JWT Claims
{
  "sub": "alice@fintech.com",
  "email": "alice@fintech.com",
  "organization": "FinTech Corp",
  "business_unit": "Analytics",
  "team": "Reporting",
  "roles": ["analyst"],
  "exp": 1700000000
}
Output: Security Context
{
  "company": "FinTech Corp",
  "business_unit": "Analytics",
  "team": "Reporting",
  "user": "alice@fintech.com",
  "roles": ["analyst"]
}

Policy Resolution Chain

The security context flows through the policy resolver for hierarchical lookup:

security_context = {
  "company": "FinTech Corp",
  "business_unit": "Analytics",
  "team": "Reporting",
  "user": "alice@fintech.com",
  "roles": ["analyst"]
}

Lookup Chain:
1. base:role:analyst           → GPT-3.5, 500 tokens (starting point)
2. restrict:org:fintech-corp   → No secrets, audit required
3. restrict:bu:analytics       → Low temperature, consistency mode
4. restrict:team:reporting     → 9-6 EST only, specific data sources
5. filter:clearance:standard   → No executive data access

Final Policy (Most Restrictive):
- Model: GPT-3.5 ONLY
- Tokens: 500 MAX
- Hours: 9-6 EST
- Data: Standard clearance only
- Audit: Full logging required

Implementation

The conversion happens automatically in the MACAW Client layer. Applications just pass the JWT token:

Python
from macaw_adapters.openai import SecureOpenAI

# Initialize adapter with your app
client = SecureOpenAI(app_name="financial-analyzer")

# Pass JWT token from your identity provider
# (MACAW handles the conversion internally)
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Analyze Q4 report"}],
    jwt_token=alice_jwt  # JWT from Keycloak/Okta/Azure AD
)

# Behind the scenes:
# 1. JWT validated and claims extracted
# 2. Claims mapped via .claims-config.yaml
# 3. security_context created
# 4. Hierarchical policy lookup
# 5. Constraints applied (may downgrade model)
# 6. Request executed with Alice's permissions

Multi-User Safety

The key security property: no identity bleed possible. Each request creates a fresh security context from its JWT:

Concurrent Multi-User Safety:
────────────────────────────

Time T1: Alice's Request
┌─────────────┐  alice_jwt  ┌─────────────────┐  security_context  ┌─────────────────┐
│ Alice       │────────────▶│ Shared          │───────────────────▶│ Alice's policies│
│ Financial   │             │ Orchestrator    │                    │ applied         │
│ Request     │             │                 │                    │                 │
└─────────────┘             │ Each request    │                    └─────────────────┘
                            │ creates fresh   │
Time T2: Bob's Request      │ security_context│
┌─────────────┐  bob_jwt    │                 │  security_context  ┌─────────────────┐
│ Bob         │────────────▶│ Same Instance!  │───────────────────▶│ Bob's policies  │
│ Analysis    │             │                 │                    │ applied         │
│ Request     │             │ NO STORED STATE │                    │                 │
└─────────────┘             └─────────────────┘                    └─────────────────┘

Key: NO identity bleed possible - each request is isolated

Stateless Design

  • • No shared state between requests
  • • Per-request context creation
  • • Isolated processing per thread
  • • Clean separation of concerns

Concurrent Safety Proof

Even if 1000 users hit the same orchestrator simultaneously, each request gets its own security_context derived from its own JWT, preventing any possibility of identity bleed.


Claim Mapping

Different identity providers use different claim names. The Claims Mapper handles this translation via .claims-config.yaml:

ProviderOrg Claim → companyUser Claim → user
Keycloakorganizationemail
OktacompanyNameemail
Azure ADcompanyNameuserPrincipalName
Google Workspacehd (hosted domain)email

See Claims Mapping for complete configuration details.


Related Topics