Skip to content

feat: As a user, I want to select a Consumer (and its Consumer Group) from a JWT claim in openid-connect on a single route. #13037

@PiyushMishra318

Description

@PiyushMishra318

Description

Feature Description

Add a consumer_selector capability to the openid-connect plugin so a single route can select a Consumer (and Consumer Group) from a JWT claim (for example, iss) before OIDC validation.

This enables deterministic multi-realm authentication on one route by mapping token claim values to Consumer identities, then applying the selected Consumer Group’s openid-connect configuration (realm-specific discovery/JWKS/introspection settings).

Motivation

Today, Consumer Group plugin configs are applied only after a Consumer is resolved.
Without a pre-auth resolver like key-auth, route-level openid-connect cannot dynamically switch realms by Consumer Group.

This forces users to:

  • duplicate routes per realm, or
  • use unsupported workaround patterns with extra auth plugins.

Proposed Behavior

Add new optional attributes in openid-connect:

  • consumer_selector.enabled (boolean)
  • consumer_selector.claim (string, default iss)
  • consumer_selector.map (object: claim_value -> consumer_name)
  • consumer_selector.strict (boolean, default true)

Request flow with selector enabled:

  1. Extract bearer token.
  2. Decode JWT payload to read selector claim.
  3. Resolve mapped Consumer by consumer_name.
  4. Attach Consumer to request context.
  5. Load selected Consumer Group’s openid-connect config.
  6. Continue normal OIDC validation and header injection (X-Userinfo, etc.) using selected config.

Compatibility / Risk Notes

  • Feature is opt-in (consumer_selector.enabled=false by default).
  • Existing openid-connect behavior is unchanged when selector is not enabled.
  • This introduces a new control path and should be reviewed for:
    • claim spoofing risks before signature verification,
    • config mismatch/fallback behavior,
    • interaction with existing plugin execution order.

Example Config

"openid-connect": {
  "client_id": "dummy",
  "client_secret": "dummy",
  "discovery": "https://idp.example/.well-known/openid-configuration",
  "bearer_only": true,
  "consumer_selector": {
    "enabled": true,
    "claim": "iss",
    "strict": true,
    "map": {
      "https://idp.example/realms/realm-a": "realm-a-consumer",
      "https://idp.example/realms/realm-b": "realm-b-consumer"
    }
  }
}

If this design direction is acceptable, I can split this into smaller PRs (schema/docs first, runtime behavior second) if preferred.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    📋 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions