[PR #22867] [CLOSED] feat: Add OAUTH_AUTHORIZE_PARAMS env var for extra OIDC authorization redirect parameters #65752

Closed
opened 2026-05-06 11:41:10 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/22867
Author: @rndmcnlly
Created: 3/19/2026
Status: Closed

Base: devHead: feat/oauth-authorize-params


📝 Commits (1)

  • 966a033 feat: add OAUTH_AUTHORIZE_PARAMS for extra OIDC authorization redirect params

📊 Changes

2 files changed (+15 additions, -0 deletions)

View changed files

📝 backend/open_webui/config.py (+6 -0)
📝 backend/open_webui/utils/oauth.py (+9 -0)

📄 Description

Description

Adds OAUTH_AUTHORIZE_PARAMS, a new environment variable that lets operators inject arbitrary extra query parameters into the OIDC authorization redirect URL — without code changes or a custom fork.

Closes #22863


Problem

When Open WebUI uses an OIDC broker — a provider that itself presents a picker UI for choosing among upstream identity providers — the /oauth/oidc/login redirect drops users on the broker's full picker page. In deployments where only one upstream IdP is valid this causes two problems:

  1. User confusion. The picker lists hundreds or thousands of options (e.g. CILogon lists ~5,000 academic institutions). Users don't know what to pick.
  2. Silent wrong-IdP failure. A user who picks the wrong IdP (e.g. Google) authenticates successfully at the broker, then hits OAUTH_ALLOWED_DOMAINS and receives a generic "Invalid credentials" error with no guidance. They completed what looked like a successful login.

Every major OIDC broker provides a query parameter to pre-select or restrict the upstream IdP on the authorization endpoint:

Broker Parameter
CILogon (InCommon / research federations) idphint=<entityID>
Keycloak kc_idp_hint=<alias>
Dex connector_id=<id>

There was previously no way to pass these through Open WebUI configuration.


Solution

OAUTH_AUTHORIZE_PARAMS accepts a JSON object. Its entries are merged into the **kwargs passed to authlib's client.authorize_redirect() in handle_login(), which passes them verbatim to the authorization URL query string.

Example usage:

# CILogon — show only UC Santa Cruz in the IdP picker
OAUTH_AUTHORIZE_PARAMS={"idphint": "urn:mace:incommon:ucsc.edu"}

# Keycloak — bypass broker picker, go directly to a configured upstream IdP
OAUTH_AUTHORIZE_PARAMS={"kc_idp_hint": "google"}

# Any provider — require MFA even when a session already exists
OAUTH_AUTHORIZE_PARAMS={"acr_values": "https://refeds.org/profile/mfa"}

# CILogon with multiple params (skin + IdP restriction)
OAUTH_AUTHORIZE_PARAMS={"idphint": "urn:mace:incommon:ucsc.edu", "skin": "myapp"}

Implementation

backend/open_webui/config.py — new PersistentConfig alongside OAUTH_AUDIENCE:

OAUTH_AUTHORIZE_PARAMS = PersistentConfig(
    "OAUTH_AUTHORIZE_PARAMS",
    "oauth.oidc.authorize_params",
    os.environ.get("OAUTH_AUTHORIZE_PARAMS", ""),
)

backend/open_webui/utils/oauth.py — three additions: import, config wire-up, and handle_login logic:

if auth_manager_config.OAUTH_AUTHORIZE_PARAMS:
    try:
        extra = json.loads(auth_manager_config.OAUTH_AUTHORIZE_PARAMS)
        if isinstance(extra, dict):
            kwargs.update(extra)
    except (json.JSONDecodeError, TypeError):
        log.warning("OAUTH_AUTHORIZE_PARAMS is not valid JSON, ignoring")

Why this is small: authlib already passes **kwargs verbatim through authorize_redirect()create_authorization_url()prepare_grant_uri() → URL query string. The library does the right thing — OWUI just needed a way to populate those kwargs from config.

Direct precedent: OAUTH_AUDIENCE (PR #19768) uses this exact mechanism for a single hardcoded key. This generalises that pattern to an arbitrary JSON dict.


Checklist

  • Targets dev branch
  • No new dependencies
  • No frontend changes (all OAuth config is env-var only)
  • Only affects the generic oidc provider path — Google, Microsoft, GitHub, Feishu unaffected
  • Invalid JSON: caught, logged as warning, no crash
  • Non-dict JSON (e.g. array): silently ignored
  • OAUTH_AUDIENCE behaviour unchanged
  • Self-review complete
  • Manual testing performed (see below)

Testing

Isolation tests (sandbox)

Full integration testing was not possible in the sandbox environment (1 GB cgroup memory limit prevents installing the complete dependency set). The following isolation tests were performed and all passed:

  • AST parse of both modified files
  • All edge cases of the handle_login kwargs block in isolation: empty/default (no-op), idphint happy path, coexistence with OAUTH_AUDIENCE, acr_values, invalid JSON (warns, doesn't crash), JSON array (silently ignored)
  • URL propagation: confirmed kwargs of this shape reach the query string via urllib.parse, matching authlib's prepare_grant_uri behaviour
  • Env var → default value round-trip for both present and absent OAUTH_AUTHORIZE_PARAMS

Integration test — CILogon with idphint (human-verified)

A local Open WebUI instance was started from this branch and configured with a CILogon OIDC client that has http://localhost:8080/oauth/oidc/callback as an allowed redirect:

OPENID_PROVIDER_URL=https://cilogon.org/.well-known/openid-configuration
OAUTH_SCOPES="openid email profile org.cilogon.userinfo"
OAUTH_AUTHORIZE_PARAMS={"idphint": "urn:mace:incommon:ucsc.edu"}

Results:

  1. Redirect URL confirmed. The /oauth/oidc/login endpoint redirected to CILogon with idphint=urn%3Amace%3Aincommon%3Aucsc.edu present in the authorization URL query string.
  2. IdP restriction worked. CILogon skipped its ~5,000-institution picker and went directly to UC Santa Cruz's Shibboleth login page.
  3. Full OIDC round-trip succeeded. After authenticating with UC Santa Cruz credentials, the callback completed and the user was signed in to Open WebUI.
  4. Control test. Manually removing idphint from the authorization URL restored the full CILogon institution picker, confirming the parameter was responsible for the restriction. Logging in via a different institution (UC Irvine) also succeeded, confirming the feature does not break the standard flow.

Changelog Entry

Added

  • OAUTH_AUTHORIZE_PARAMS environment variable: a JSON object of extra query parameters to append to the OIDC authorization redirect URL. Enables operators using OIDC brokers (CILogon, Keycloak, Dex, etc.) to pre-select or restrict the upstream identity provider without code changes. Invalid JSON is caught and logged as a warning; non-dict JSON is silently ignored. Only applies to the generic oidc provider path.

Additional Information

  • Related issue: [PR #12194] [MERGED] i18n: update zh-TW (#22863)
  • Precedent PR: #19768 (OAUTH_AUDIENCE — same mechanism, single hardcoded key)
  • The authlib call chain was verified by reading authlib v1.6.9 source: authorize_redirect(**kwargs)create_authorization_url(**kwargs)prepare_grant_uri(**kwargs) — kwargs become URL query params verbatim.

Screenshots or Videos

N/A — the change is server-side only (no UI). Observable effect is the extra query parameters appearing in the browser's address bar during the OAuth redirect to the identity provider.


Contributor License Agreement


Disclosure: this PR was researched and drafted using the Lathe coding agent toolkit inside of Open WebUI. The implementation, all test cases, and this description were reviewed and approved by the human author before submission.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/22867 **Author:** [@rndmcnlly](https://github.com/rndmcnlly) **Created:** 3/19/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `feat/oauth-authorize-params` --- ### 📝 Commits (1) - [`966a033`](https://github.com/open-webui/open-webui/commit/966a033cf00de6692304e861e036449445027b54) feat: add OAUTH_AUTHORIZE_PARAMS for extra OIDC authorization redirect params ### 📊 Changes **2 files changed** (+15 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/config.py` (+6 -0) 📝 `backend/open_webui/utils/oauth.py` (+9 -0) </details> ### 📄 Description ## Description Adds `OAUTH_AUTHORIZE_PARAMS`, a new environment variable that lets operators inject arbitrary extra query parameters into the OIDC authorization redirect URL — without code changes or a custom fork. Closes #22863 --- ## Problem When Open WebUI uses an OIDC **broker** — a provider that itself presents a picker UI for choosing among upstream identity providers — the `/oauth/oidc/login` redirect drops users on the broker's full picker page. In deployments where only one upstream IdP is valid this causes two problems: 1. **User confusion.** The picker lists hundreds or thousands of options (e.g. CILogon lists ~5,000 academic institutions). Users don't know what to pick. 2. **Silent wrong-IdP failure.** A user who picks the wrong IdP (e.g. Google) authenticates successfully at the broker, then hits `OAUTH_ALLOWED_DOMAINS` and receives a generic "Invalid credentials" error with no guidance. They completed what looked like a successful login. Every major OIDC broker provides a query parameter to pre-select or restrict the upstream IdP on the authorization endpoint: | Broker | Parameter | |---|---| | CILogon (InCommon / research federations) | `idphint=<entityID>` | | Keycloak | `kc_idp_hint=<alias>` | | Dex | `connector_id=<id>` | There was previously no way to pass these through Open WebUI configuration. --- ## Solution `OAUTH_AUTHORIZE_PARAMS` accepts a JSON object. Its entries are merged into the `**kwargs` passed to authlib's `client.authorize_redirect()` in `handle_login()`, which passes them verbatim to the authorization URL query string. **Example usage:** ```env # CILogon — show only UC Santa Cruz in the IdP picker OAUTH_AUTHORIZE_PARAMS={"idphint": "urn:mace:incommon:ucsc.edu"} # Keycloak — bypass broker picker, go directly to a configured upstream IdP OAUTH_AUTHORIZE_PARAMS={"kc_idp_hint": "google"} # Any provider — require MFA even when a session already exists OAUTH_AUTHORIZE_PARAMS={"acr_values": "https://refeds.org/profile/mfa"} # CILogon with multiple params (skin + IdP restriction) OAUTH_AUTHORIZE_PARAMS={"idphint": "urn:mace:incommon:ucsc.edu", "skin": "myapp"} ``` --- ## Implementation **`backend/open_webui/config.py`** — new `PersistentConfig` alongside `OAUTH_AUDIENCE`: ```python OAUTH_AUTHORIZE_PARAMS = PersistentConfig( "OAUTH_AUTHORIZE_PARAMS", "oauth.oidc.authorize_params", os.environ.get("OAUTH_AUTHORIZE_PARAMS", ""), ) ``` **`backend/open_webui/utils/oauth.py`** — three additions: import, config wire-up, and `handle_login` logic: ```python if auth_manager_config.OAUTH_AUTHORIZE_PARAMS: try: extra = json.loads(auth_manager_config.OAUTH_AUTHORIZE_PARAMS) if isinstance(extra, dict): kwargs.update(extra) except (json.JSONDecodeError, TypeError): log.warning("OAUTH_AUTHORIZE_PARAMS is not valid JSON, ignoring") ``` **Why this is small:** authlib already passes `**kwargs` verbatim through `authorize_redirect()` → `create_authorization_url()` → `prepare_grant_uri()` → URL query string. The library does the right thing — OWUI just needed a way to populate those kwargs from config. **Direct precedent:** `OAUTH_AUDIENCE` (PR #19768) uses this exact mechanism for a single hardcoded key. This generalises that pattern to an arbitrary JSON dict. --- ## Checklist - [x] Targets `dev` branch - [x] No new dependencies - [x] No frontend changes (all OAuth config is env-var only) - [x] Only affects the generic `oidc` provider path — Google, Microsoft, GitHub, Feishu unaffected - [x] Invalid JSON: caught, logged as warning, no crash - [x] Non-dict JSON (e.g. array): silently ignored - [x] `OAUTH_AUDIENCE` behaviour unchanged - [x] Self-review complete - [x] Manual testing performed (see below) --- ## Testing ### Isolation tests (sandbox) Full integration testing was not possible in the sandbox environment (1 GB cgroup memory limit prevents installing the complete dependency set). The following isolation tests were performed and all passed: - AST parse of both modified files - All edge cases of the `handle_login` kwargs block in isolation: empty/default (no-op), `idphint` happy path, coexistence with `OAUTH_AUDIENCE`, `acr_values`, invalid JSON (warns, doesn't crash), JSON array (silently ignored) - URL propagation: confirmed kwargs of this shape reach the query string via `urllib.parse`, matching authlib's `prepare_grant_uri` behaviour - Env var → default value round-trip for both present and absent `OAUTH_AUTHORIZE_PARAMS` ### Integration test — CILogon with `idphint` (human-verified) A local Open WebUI instance was started from this branch and configured with a CILogon OIDC client that has `http://localhost:8080/oauth/oidc/callback` as an allowed redirect: ```env OPENID_PROVIDER_URL=https://cilogon.org/.well-known/openid-configuration OAUTH_SCOPES="openid email profile org.cilogon.userinfo" OAUTH_AUTHORIZE_PARAMS={"idphint": "urn:mace:incommon:ucsc.edu"} ``` **Results:** 1. **Redirect URL confirmed.** The `/oauth/oidc/login` endpoint redirected to CILogon with `idphint=urn%3Amace%3Aincommon%3Aucsc.edu` present in the authorization URL query string. 2. **IdP restriction worked.** CILogon skipped its ~5,000-institution picker and went directly to UC Santa Cruz's Shibboleth login page. 3. **Full OIDC round-trip succeeded.** After authenticating with UC Santa Cruz credentials, the callback completed and the user was signed in to Open WebUI. 4. **Control test.** Manually removing `idphint` from the authorization URL restored the full CILogon institution picker, confirming the parameter was responsible for the restriction. Logging in via a different institution (UC Irvine) also succeeded, confirming the feature does not break the standard flow. --- ## Changelog Entry ### Added - `OAUTH_AUTHORIZE_PARAMS` environment variable: a JSON object of extra query parameters to append to the OIDC authorization redirect URL. Enables operators using OIDC brokers (CILogon, Keycloak, Dex, etc.) to pre-select or restrict the upstream identity provider without code changes. Invalid JSON is caught and logged as a warning; non-dict JSON is silently ignored. Only applies to the generic `oidc` provider path. --- ### Additional Information - Related issue: #22863 - Precedent PR: #19768 (`OAUTH_AUDIENCE` — same mechanism, single hardcoded key) - The authlib call chain was verified by reading authlib v1.6.9 source: `authorize_redirect(**kwargs)` → `create_authorization_url(**kwargs)` → `prepare_grant_uri(**kwargs)` — kwargs become URL query params verbatim. ### Screenshots or Videos N/A — the change is server-side only (no UI). Observable effect is the extra query parameters appearing in the browser's address bar during the OAuth redirect to the identity provider. --- ### Contributor License Agreement - [x] By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. --- ✨ Disclosure: this PR was researched and drafted using the [Lathe](https://lathe.tools/) coding agent toolkit inside of Open WebUI. The implementation, all test cases, and this description were reviewed and approved by the human author before submission. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-06 11:41:10 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#65752