Skip to main content

Event Hooks for SSO Login

Use a Python callback to read a verified identity from an upstream authentication proxy or customize the identity returned after an SSO sign-in.

Enterprise feature

SSO requires a LiteLLM Enterprise license. Start a free 30-day trial or book a demo. See what Enterprise includes.

SSO is free for up to 5 users. Beyond that, an enterprise license is required. The custom UI sign-in hook for an upstream authentication proxy requires Enterprise.

How it works​

Choose the hook that matches where authentication happens:

HookWhen it runsReturn value
custom_ui_sso_sign_in_handlerAn upstream authentication proxy has authenticated the user; the hook reads its identity headers.OpenID
custom_ssoLiteLLM has completed its provider sign-in flow; the callback receives the provider's user information.SSOUserDefinedValues

LiteLLM uses the returned identity to complete sign-in. Configure roles, team membership, and restrictions through SSO permissions.

Prerequisites​

Use a working LiteLLM deployment with the Admin UI, database, and master key configured. Put the handler module beside config.yaml or on the proxy's Python import path.

For the upstream-proxy hook, configure the proxy to authenticate requests, strip client-supplied identity headers, and set its own verified values. Restrict direct access to LiteLLM to that proxy. Set general_settings.trusted_proxy_ranges to its direct peer IPs or CIDRs; LiteLLM rejects header-based sign-in from untrusted peers.

For the post-sign-in callback, first configure OpenID Connect or SAML and verify a normal sign-in.

Setup​

Read identity headers from an authentication proxy​

Save this as custom_ui_sso.py. Adjust the header names to match your authentication proxy. Reject missing identities instead of assigning a shared placeholder user.

custom_ui_sso.py
from fastapi import HTTPException, Request
from fastapi_sso.sso.base import OpenID
from litellm.integrations.custom_sso_handler import CustomSSOLoginHandler


class HeaderIdentityHandler(CustomSSOLoginHandler):
async def handle_custom_ui_sso_sign_in(self, request: Request) -> OpenID:
user_id = request.headers.get("x-forwarded-user") or request.headers.get("x-user")
email = request.headers.get("x-forwarded-email") or request.headers.get("x-email")
if not user_id or not email:
raise HTTPException(status_code=401, detail="Missing authenticated identity")
display_name = (
request.headers.get("x-forwarded-preferred-username")
or request.headers.get("x-preferred-username")
or user_id
)
return OpenID(
id=user_id,
email=email,
display_name=display_name,
provider="oauth-proxy",
)


custom_ui_sso_sign_in_handler = HeaderIdentityHandler()

Add the handler instance to your existing configuration. Replace the example address with your authentication proxy's direct peer address:

config.yaml
general_settings:
custom_ui_sso_sign_in_handler: custom_ui_sso.custom_ui_sso_sign_in_handler
trusted_proxy_ranges: ["10.0.0.10/32"]

Customize the identity after provider sign-in​

Save this as custom_sso.py. The callback receives provider user information after sign-in and returns the stable user ID and email LiteLLM should use.

custom_sso.py
from fastapi_sso.sso.base import OpenID
from litellm.proxy._types import SSOUserDefinedValues


async def custom_sso_handler(userIDPInfo: OpenID) -> SSOUserDefinedValues:
if not userIDPInfo.id:
raise ValueError("The identity provider returned no user ID")
return SSOUserDefinedValues(
user_id=userIDPInfo.id,
user_email=userIDPInfo.email,
user_role=None,
)

user_role=None preserves the stored LiteLLM role; new users default to internal_user_viewer. An explicit role overrides it on every login. Configure role assignment in SSO permissions.

Add the callback to the same configuration that contains your provider settings:

config.yaml
general_settings:
custom_sso: custom_sso.custom_sso_handler

Restart the proxy after configuring either hook:

litellm --config config.yaml

Test sign-in​

For the upstream-proxy hook, open the Admin UI through the authentication proxy and sign in with a test account. Confirm LiteLLM shows that account. A request from the trusted proxy with missing identity headers should be rejected by the example handler; a direct request from an untrusted peer should also fail.

For the post-sign-in callback, start a fresh browser session, sign in through your configured provider, and confirm the expected account opens in LiteLLM. Sign in again to check that the stable user ID resolves to the same account.

Configuration reference​

Setting or callbackContract
general_settings.custom_ui_sso_sign_in_handlerModule path to an instance of CustomSSOLoginHandler.
handle_custom_ui_sso_sign_in(request)Async method returning an OpenID identity from the trusted request.
general_settings.trusted_proxy_rangesDirect peer IPs or CIDRs allowed to supply identity headers.
general_settings.custom_ssoModule path to an async function receiving provider user information.
SSOUserDefinedValuesSupplies user_id, user_email, and optional overrides. See SSO permissions for permission fields.

Read additional provider fields​

For a generic provider, set GENERIC_USER_EXTRA_ATTRIBUTES to the fields needed by your callback. They are available through getattr(userIDPInfo, "extra_fields", None) or {}. See OIDC provider field mapping for configuration.

Use the returned identity for authentication. For user and team lifecycle operations, see identity provisioning.

Troubleshooting​

SymptomCheck
Handler cannot be importedConfirm the module path and mounted Python file. The header hook refers to an instance; custom_sso refers to a function.
Header sign-in reports an untrusted proxyConfigure trusted_proxy_ranges for the direct peer that reaches LiteLLM, and confirm the request passes through that proxy.
Header sign-in reports a missing identityConfirm the authentication proxy sets the expected headers after validating the user.
user_custom_sso must be a coroutine functionDefine the post-sign-in callback with async def.
Repeated sign-ins create different usersReturn a stable, nonempty provider ID instead of a changing email or display name.
Roles or teams are wrong after sign-inCheck SSO permissions and any explicit callback overrides.

Configure providers through OpenID Connect or SAML. Use SSO permissions for access policies, identity provisioning for user lifecycle management, and Custom Auth for API request handlers.