apache / apache/apisix

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.

Open
#13,037 2 comments 1 reaction 0 assignees View on GitHub
feature-request
Dominant language
Lua
Stars
17.1k
Forks
2.9k
Avg merge
3d 16h
Merged PRs (30d)
63

Description

### 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

```json
"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.

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing openid-connect plugin schema and runtime authentication flow, including how Consumer Groups are resolved and configured. Define the schema, documentation, and runtime changes needed so an enabled selector maps a JWT claim to a Consumer before validation, while preserving the disabled path and covering spoofing, fallback, and execution-order behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua
Domain
authentication
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.