Skip to content

OIDC Claims Distribution — Distributed and Aggregated Claims Explained

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about OIDC Claims Distribution. We cover key concepts, practical examples, and best practices to help you master this topic.

Distributed and aggregated claims in Openid Connect allow an identity provider to include claims sourced from external services, enabling scenarios where user attributes are spread across multiple trusted providers.

What You'll Learn

  • What distributed claims are and when to use them
  • What aggregated claims are and how they differ from distributed
  • How to resolve external claim sources securely

Why It Matters

User attributes often come from multiple sources. A primary identity provider knows your email and name, but a partner service knows your shipping address or subscription level. OIDC claims distribution lets providers include these external attributes in a single OIDC response without the user logging into each service separately.

Real-World Use

DodaTech employees authenticate via the corporate OIDC provider (Azure AD). The provider includes an aggregated claim for the employee's security clearance level from a separate HR system. Instead of fetching clearance data separately, the ID token contains it directly through claims aggregation.

flowchart LR
    A["OIDC Provider"] -->|"Claims include\n_source or _claim_sources"| B["Your App"]
    C["External Service 1"] -->|"Distributed Claims"| A
    D["External Service 2"] -->|"Aggregated Claims"| A
    style A fill:#dbeafe,stroke:#2563eb
    style C fill:#fef3c7,stroke:#d97706
    style D fill:#bbf7d0,stroke:#16a34a

Distributed Claims

Distributed claims reference an external endpoint that returns the claim value. The ID token includes a _claim_names and _claim_sources structure pointing to the external source:

{
  "sub": "user123",
  "name": "Jane Doe",
  "_claim_names": {
    "shipping_address": "src1",
    "loyalty_tier": "src2"
  },
  "_claim_sources": {
    "src1": {
      "endpoint": "https://shipping.example.com/claims/jane",
      "access_token": "eyJhbGci..."
    },
    "src2": {
      "endpoint": "https://loyalty.example.com/tier/jane",
      "access_token": "eyJhbGci..."
    }
  }
}

Aggregated Claims

Aggregated claims embed a complete JWT from an external source directly in the _claim_sources field. The external claims are pre-packaged as a signed JWT that your application can verify independently:

{
  "sub": "user123",
  "name": "Jane Doe",
  "_claim_names": {
    "hr_data": "src_hr"
  },
  "_claim_sources": {
    "src_hr": {
      "JWT": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiZGVwYXJ0bWVudCI6IkVuZ2luZWVyaW5nIiwicm9sZSI6IkFkbWluIiwiaXNzIjoiaHJAc3lzdGVtLmV4YW1wbGUuY29tIn0.signature"
    }
  }
}

Resolving Distributed Claims

import requests
import jwt

def resolve_distributed_claims(token_payload):
    claims_to_resolve = token_payload.get("_claim_names", {})
    claim_sources = token_payload.get("_claim_sources", {})
    resolved = {}

    for claim_name, source_key in claims_to_resolve.items():
        source = claim_sources.get(source_key)
        if not source:
            continue

        endpoint = source.get("endpoint")
        access_token = source.get("access_token")
        if not endpoint:
            continue

        response = requests.get(
            endpoint,
            headers={"Authorization": f"Bearer {access_token}"}
        )
        if response.status_code == 200:
            resolved[claim_name] = response.json()

    return resolved

Verifying Aggregated Claims

import jwt
import requests

def verify_aggregated_claim(aggregated_jwt, trusted_issuer):
    # Fetch the external provider's JWKS
    jwks_uri = f"{trusted_issuer}/.well-known/jwks.json"
    jwks = requests.get(jwks_uri).json()

    header = jwt.get_unverified_header(aggregated_jwt)
    key = next(k for k in jwks["keys"] if k["kid"] == header["kid"])

    payload = jwt.decode(
        aggregated_jwt,
        key,
        algorithms=["RS256"],
        issuer=trusted_issuer
    )
    return payload

Common Mistakes

1. Not Verifying External JWT Signatures

Aggregated claims come as signed JWTs. Always verify the signature against the external provider's JWKS, not the main provider's keys.

2. Trusting Distributed Claims Without Access Token Validation

Distributed claim endpoints require an access token. Verify this token has the correct scope before accepting the claims.

3. Cacheing Claims Indefinitely

Distributed and aggregated claims can change. Implement TTL-based Caching and re-fetch when stale.

4. Ignoring the Source JWT Issuer

When resolving aggregated claims, always check the iss field matches the expected external provider. An attacker could embed a JWT from an untrusted source.

5. Mixing Distributed and Aggregated Access Tokens

Distributed claims use access tokens for the external endpoint. These are different from the main OIDC access token. Do not reuse them.

Practice Questions

  1. What is the difference between distributed and aggregated claims?
  2. How does the _claim_names field work?
  3. Why would you use aggregated claims instead of distributed?
  4. How do you verify an aggregated claim JWT?
  5. What security checks are needed for distributed claims?

Answers

  1. Distributed claims reference an external endpoint; aggregated claims embed a signed JWT. 2. It maps claim names to source keys in _claim_sources. 3. Aggregated claims work offline since the JWT is self-contained. 4. Verify the JWT signature against the external provider's JWKS. 5. Validate the access token and endpoint URL.

Challenge

Build a claims resolver that takes an ID token payload with both distributed and aggregated claims, fetches and verifies each source, merges them into a flat claims dictionary, and caches results with a configurable TTL.

FAQ

What are distributed claims in OIDC?

Claims whose values are fetched from external endpoints referenced in the _claim_sources field.

What are aggregated claims in OIDC?

Claims whose values are embedded as signed JWTs from external providers within the _claim_sources field.

How does the _claim_names field work?

It maps claim names to source identifiers that index into _claim_sources.

Do all OIDC providers support distributed claims?

No. Support varies by provider. Check the provider's documentation and supported claims.

Can distributed claims be cached?

Yes, but implement TTL-based invalidation since external claim values can change.

Mini Project

Build a claims distribution server that acts as an external claim source for an OIDC provider. The server should accept access tokens, return claims in the distributed format, sign aggregated claim JWTs for offline verification, and include proper error responses.

What's Next

  • Explore pairwise identifiers for anonymous yet consistent user identification
  • Learn about dynamic client registration for automated provider setup
  • Continue to OIDC client types for web, mobile, and SPA applications

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro