diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 26a8d376c5..e734a2f865 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -525,6 +525,12 @@ WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get('WEBUI_AUTH_TRUSTED_NAME_HEADER' WEBUI_AUTH_TRUSTED_GROUPS_HEADER = os.environ.get('WEBUI_AUTH_TRUSTED_GROUPS_HEADER', None) WEBUI_AUTH_TRUSTED_ROLE_HEADER = os.environ.get('WEBUI_AUTH_TRUSTED_ROLE_HEADER', None) +# Custom header name for API key authentication. Defaults to 'x-api-key'. +# Useful when Open WebUI sits behind a reverse proxy / API gateway that +# already uses the Authorization header for its own authentication — set +# this to a unique header (e.g. 'X-OpenWebUI-Key') so the middleware +# checks the custom header instead and avoids the 401 short-circuit. +CUSTOM_API_KEY_HEADER = os.environ.get('CUSTOM_API_KEY_HEADER', 'x-api-key') ENABLE_PASSWORD_VALIDATION = os.environ.get('ENABLE_PASSWORD_VALIDATION', 'False').lower() == 'true' PASSWORD_VALIDATION_REGEX_PATTERN = os.environ.get( diff --git a/backend/open_webui/utils/asgi_middleware.py b/backend/open_webui/utils/asgi_middleware.py index 05389d8f94..e3872dd231 100644 --- a/backend/open_webui/utils/asgi_middleware.py +++ b/backend/open_webui/utils/asgi_middleware.py @@ -41,6 +41,7 @@ from starlette.datastructures import MutableHeaders from starlette.requests import Request from starlette.types import ASGIApp, Message, Receive, Scope, Send +from open_webui.env import CUSTOM_API_KEY_HEADER from open_webui.internal.db import ScopedSession from open_webui.utils.auth import get_http_authorization_cred @@ -119,9 +120,16 @@ class CommitSessionMiddleware: class AuthTokenMiddleware: - """Extract the bearer/cookie/x-api-key credential and stash it on + """Extract the bearer/cookie/API-key credential and stash it on `request.state.token`. + The header used for API-key transport is controlled by the + ``CUSTOM_API_KEY_HEADER`` environment variable (default ``x-api-key``). + This is useful when Open WebUI sits behind a reverse proxy that + consumes the ``Authorization`` header for its own authentication — + set the env var to a unique header (e.g. ``X-OpenWebUI-Key``) so + the middleware checks that instead and avoids the 401 short-circuit. + Routes that depend on `get_verified_user` etc. read this state. Also exposes `request.state.enable_api_keys` (snapshotted at request entry from runtime config) and stamps an `X-Process-Time` response @@ -146,7 +154,7 @@ class AuthTokenMiddleware: if cookie_token: token = HTTPAuthorizationCredentials(scheme='Bearer', credentials=cookie_token) if token is None: - api_key = request.headers.get('x-api-key') + api_key = request.headers.get(CUSTOM_API_KEY_HEADER) if api_key: token = HTTPAuthorizationCredentials(scheme='Bearer', credentials=api_key)