feat: add external OIDC issuer support for federation / cross-IdP trust#873
Open
alejandronunezcabello wants to merge 4 commits intoagentic-community:mainfrom
Open
Conversation
Adds the ability to validate JWT tokens from external OIDC-compliant identity providers alongside Keycloak tokens. This enables federation scenarios where a parent organization's IdP issues tokens that need to be validated by the registry's auth-server. Configuration: - EXTERNAL_ISSUERS: comma-separated list of trusted OIDC issuer URLs - EXTERNAL_GROUPS_CLAIM: claim name to map to registry groups (default: roles) How it works: 1. Token arrives at auth-server 2. If issuer matches an external issuer, or kid not found in Keycloak JWKS, the external issuer path is tried 3. JWKS is fetched via OIDC discovery (.well-known/openid-configuration) 4. Token is validated against the external issuer's public keys 5. The configured claim (e.g. roles) is mapped to registry groups for RBAC 6. External JWKS responses are cached (1h TTL, same as Keycloak) Backward compatible: when EXTERNAL_ISSUERS is empty (default), behavior is identical to before. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prevents UnboundLocalError when jwt.decode raises before assignment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Three fixes for Coop ChatAI federation compatibility:
1. Direct JWKS URI support: EXTERNAL_ISSUERS now accepts JSON array
with optional jwks_uri field, skipping OIDC Discovery for issuers
that don't provide .well-known/openid-configuration.
Legacy comma-separated format still works (backward compatible).
2. uid claim extraction: Username fallback chain now includes 'uid'
for issuers that use uid instead of sub (e.g. Coop ChatAI).
3. Default groups: New EXTERNAL_DEFAULT_GROUPS env var assigns
configurable groups when external tokens have no roles/groups
claims. Essential for minimal tokens that carry only user identity.
Config example for Coop ChatAI:
EXTERNAL_ISSUERS=[{"issuer":"https://chatai.coop.ch","jwks_uri":"https://chatai.coop.ch/.well-known/jwks.json"}]
EXTERNAL_DEFAULT_GROUPS=["coop-chatai-users"]
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
thank you for contributing this PR @alejandronunezcabello , so you have tested this with Keycloak and Entra? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the ability to validate JWT tokens from external OIDC-compliant identity providers alongside Keycloak tokens. This enables federation scenarios where a parent organization's IdP issues tokens that need to be validated by the registry's auth-server.
Motivation
In enterprise deployments, a registry may need to accept tokens from multiple identity providers. For example:
Currently the Keycloak provider only validates tokens from its own Keycloak instance (plus self-signed tokens). This PR adds a generic external issuer capability.
Configuration
Two new environment variables:
EXTERNAL_ISSUERSEXTERNAL_GROUPS_CLAIMrolesExample:
EXTERNAL_ISSUERS=https://login.microsoftonline.com/{tenant}/v2.0,https://accounts.google.com EXTERNAL_GROUPS_CLAIM=rolesHow it works
validate_token()issclaim matches a configured external issuer, or thekidis not found in Keycloak's JWKS, the external issuer path is tried.well-known/openid-configuration→jwks_uri)roles) is mapped to registry groups for RBACBackward compatibility
When
EXTERNAL_ISSUERSis empty (the default), behavior is identical to the current implementation. No existing functionality is affected.Changes
auth_server/providers/keycloak.py: AddedEXTERNAL_ISSUERS,EXTERNAL_GROUPS_CLAIMconfig, per-issuer JWKS cache,_get_external_jwks(),_validate_external_token(),_validate_external_token_by_kid()methods, and updatedvalidate_token()flowtests/auth_server/unit/providers/test_keycloak.py: AddedTestExternalIssuerSupporttest class with 6 tests covering discovery, caching, role mapping, multi-issuer fallback, and error casesTesting