fix: OIDC login fails when the provider adds a private JOSE header (#28065)
Logging in through CyberArk Identity dies at the callback with "Unsupported {'app_id'} in header" and the user sees "The email or password provided is incorrect". Any provider that puts a vendor-specific parameter in the ID token header hits this; CAS was already patched by name, CyberArk is the next one.
Authlib 1.7 verifies ID tokens with joserfc, which rejects header parameters it does not recognise. The old fix registered `client_id` so CAS would work, which only ever fixes one provider at a time. This turns off the unknown-header rejection instead, so any private header parameter is ignored rather than fatal. Signature verification, the algorithm allowlist, `crit` handling and value validation of registered headers all still run, so nothing that actually protects the token is relaxed.
Fixes #28062
This commit is contained in:
@@ -10,6 +10,7 @@ import urllib
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timedelta
|
||||
from functools import partialmethod
|
||||
from types import SimpleNamespace
|
||||
from typing import Literal, Optional
|
||||
|
||||
@@ -25,7 +26,6 @@ from fastapi import (
|
||||
)
|
||||
from joserfc.errors import BadSignatureError
|
||||
from joserfc.jws import JWSRegistry
|
||||
from joserfc.registry import HeaderParameter
|
||||
from mcp.shared.auth import (
|
||||
OAuthClientMetadata as MCPOAuthClientMetadata,
|
||||
)
|
||||
@@ -90,6 +90,10 @@ from open_webui.utils.misc import parse_duration
|
||||
from open_webui.utils.validate import validate_profile_image_url
|
||||
from starlette.responses import RedirectResponse
|
||||
|
||||
# Some IdPs put private params in ID token JOSE headers (CAS: client_id, CyberArk: app_id).
|
||||
# Authlib exposes no way to pass a registry, so relax it globally; crit, alg and signature checks still apply.
|
||||
JWSRegistry.__init__ = partialmethod(JWSRegistry.__init__, strict_check_header=False)
|
||||
|
||||
|
||||
class OAuthClientMetadata(MCPOAuthClientMetadata):
|
||||
token_endpoint_auth_method: Literal['none', 'client_secret_basic', 'client_secret_post'] = 'client_secret_post'
|
||||
@@ -193,14 +197,6 @@ DEFAULT_TOKEN_EXPIRY_SECONDS = 3600
|
||||
NON_EXPIRING_TOKEN_EXPIRES_AT = 253402300799 # 9999-12-31 23:59:59 UTC
|
||||
|
||||
|
||||
# Apereo CAS includes client_id in ID token JWS headers; Authlib 1.7/joserfc
|
||||
# rejects unknown headers unless we register the provider extension.
|
||||
JWSRegistry.default_header_registry.setdefault(
|
||||
'client_id',
|
||||
HeaderParameter('OAuth client identifier', 'str'),
|
||||
)
|
||||
|
||||
|
||||
def _normalize_token_expiry(token: dict) -> dict:
|
||||
"""Ensure a token dict always has a numeric ``expires_at``.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user