{"id":1923,"date":"2026-03-07T02:27:26","date_gmt":"2026-03-07T00:27:26","guid":{"rendered":"https:\/\/cln.io\/blog\/?p=1923"},"modified":"2026-03-10T21:06:41","modified_gmt":"2026-03-10T19:06:41","slug":"litellm-authentik-sso-full-admin-access-with-automatic-role-mapping","status":"publish","type":"post","link":"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/","title":{"rendered":"LiteLLM + Authentik SSO: Full Admin Access with Automatic Role Mapping"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/BerriAI\/litellm\">LiteLLM<\/a> is an OpenAI-compatible proxy that lets you route requests to multiple LLM providers through a single API. It has a built-in admin UI with SSO support. <a href=\"https:\/\/goauthentik.io\/\">Authentik<\/a> is an open-source identity provider that supports OAuth2\/OIDC out of the box.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide shows you how to wire them together so users can log into LiteLLM via Authentik and <strong>automatically get the <code>proxy_admin<\/code> role<\/strong> &#8211; no manual role assignment needed.<\/p>\n\n\n\n<nav aria-label=\"Table of Contents\" class=\"wp-block-table-of-contents\"><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#the-end-result\">The End Result<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#what-you-need\">What You Need<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#part-1-authentik-configuration\">Part 1: Authentik Configuration<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#1-create-a-scope-mapping-for-the-litellm-role\">1. Create a Scope Mapping for the LiteLLM Role<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#2-create-an-oauth2-openid-provider\">2. Create an OAuth2\/OpenID Provider<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#3-create-an-application\">3. Create an Application<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#part-2-litellm-configuration\">Part 2: LiteLLM Configuration<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#how-the-flow-works\">How the Flow Works<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#bonus-auto-redirect-and-logout\">Bonus: Auto-Redirect and Logout<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#skip-the-login-page-with-auto-redirect-ui-login-to-sso\">Skip the login page with AUTO_REDIRECT_UI_LOGIN_TO_SSO<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#proper-logout-with-proxy-logout-url\">Proper logout with PROXY_LOGOUT_URL<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#gotchas\">Gotchas<\/a><ol><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#email-validation\">Email validation<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#role-is-persisted-on-first-login\">Role is persisted on first login<\/a><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#self-signed-certificates\">Self-signed certificates<\/a><\/li><\/ol><\/li><li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/cln.io\/blog\/litellm-authentik-sso-full-admin-access-with-automatic-role-mapping\/#docker-compose-example\">Docker Compose Example<\/a><\/li><\/ol><\/nav>\n\n\n\n<h2 id=\"the-end-result\" class=\"wp-block-heading\">The End Result<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After setup, visiting the LiteLLM UI automatically redirects to Authentik. After authenticating, the user lands on the full admin dashboard.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/01-litellm-login.png\" alt=\"LiteLLM login page with SSO button\" class=\"wp-image-2090\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/01-litellm-login.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/01-litellm-login-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/01-litellm-login-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/01-litellm-login-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">The LiteLLM login page &#8211; click &#8220;Login with SSO&#8221; to authenticate via Authentik.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/02-authentik-login.png\" alt=\"Authentik login page\" class=\"wp-image-2091\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/02-authentik-login.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/02-authentik-login-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/02-authentik-login-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/02-authentik-login-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">Authentik handles the authentication.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/03-authentik-password.png\" alt=\"Authentik password prompt\" class=\"wp-image-2092\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/03-authentik-password.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/03-authentik-password-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/03-authentik-password-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/03-authentik-password-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">Enter your credentials on Authentik.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/04-litellm-dashboard.png\" alt=\"LiteLLM admin dashboard after SSO login\" class=\"wp-image-2093\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/04-litellm-dashboard.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/04-litellm-dashboard-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/04-litellm-dashboard-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/04-litellm-dashboard-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">After login: the full proxy_admin dashboard with all management sections.<\/figcaption><\/figure>\n\n\n\n<h2 id=\"what-you-need\" class=\"wp-block-heading\">What You Need<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A running Authentik instance<\/li>\n\n\n\n<li>A running LiteLLM Proxy instance (with Postgres)<\/li>\n\n\n\n<li>Both accessible over HTTPS<\/li>\n<\/ul>\n\n\n\n<h2 id=\"part-1-authentik-configuration\" class=\"wp-block-heading\">Part 1: Authentik Configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Three things to set up in the Authentik admin UI:<\/p>\n\n\n\n<h3 id=\"1-create-a-scope-mapping-for-the-litellm-role\" class=\"wp-block-heading\">1. Create a Scope Mapping for the LiteLLM Role<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is the key piece. LiteLLM reads a <code>litellm_role<\/code> claim from the OIDC userinfo response to determine the user&#8217;s role. We need Authentik to include this claim.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Go to <strong>Customization \u2192 Property Mappings \u2192 Create \u2192 Scope Mapping<\/strong> and set:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Setting<\/th><th>Value<\/th><\/tr><\/thead><tbody><tr><td><strong>Name<\/strong><\/td><td><code>LiteLLM Role<\/code><\/td><\/tr><tr><td><strong>Scope name<\/strong><\/td><td><code>litellm_role<\/code><\/td><\/tr><tr><td><strong>Expression<\/strong><\/td><td><code>return {\"litellm_role\": \"proxy_admin\"}<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/08-authentik-scope-mapping.png\" alt=\"LiteLLM Role scope mapping in Authentik\" class=\"wp-image-2096\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/08-authentik-scope-mapping.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/08-authentik-scope-mapping-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/08-authentik-scope-mapping-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/08-authentik-scope-mapping-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">The &#8220;LiteLLM Role&#8221; scope mapping in the Property Mappings list.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/09-authentik-scope-mapping-detail.png\" alt=\"Scope mapping detail showing expression\" class=\"wp-image-2097\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/09-authentik-scope-mapping-detail.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/09-authentik-scope-mapping-detail-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/09-authentik-scope-mapping-detail-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/09-authentik-scope-mapping-detail-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">The scope mapping expression that returns the proxy_admin role.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What this does:<\/strong> When LiteLLM requests the <code>litellm_role<\/code> scope during the OIDC flow, Authentik returns <code>{\"litellm_role\": \"proxy_admin\"}<\/code> in the userinfo response. LiteLLM reads this and assigns the role on first login.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Want different roles per user?<\/strong> You can make the expression conditional based on group membership:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">if ak_is_group_member(request.user, name=\"admins\"):\n    return {\"litellm_role\": \"proxy_admin\"}\nreturn {\"litellm_role\": \"internal_user\"}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Valid roles: <code>proxy_admin<\/code>, <code>proxy_admin_viewer<\/code>, <code>internal_user<\/code>, <code>internal_user_view_only<\/code><\/p>\n\n\n\n<h3 id=\"2-create-an-oauth2-openid-provider\" class=\"wp-block-heading\">2. Create an OAuth2\/OpenID Provider<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Go to <strong>Applications \u2192 Providers \u2192 Create \u2192 OAuth2\/OpenID Provider<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Setting<\/th><th>Value<\/th><\/tr><\/thead><tbody><tr><td><strong>Name<\/strong><\/td><td><code>LiteLLM Provider<\/code><\/td><\/tr><tr><td><strong>Authorization flow<\/strong><\/td><td><code>default-provider-authorization-implicit-consent<\/code><\/td><\/tr><tr><td><strong>Client type<\/strong><\/td><td>Confidential<\/td><\/tr><tr><td><strong>Client ID<\/strong><\/td><td><code>litellm<\/code><\/td><\/tr><tr><td><strong>Client Secret<\/strong><\/td><td><code>litellm-client-secret<\/code> (use your own)<\/td><\/tr><tr><td><strong>Redirect URIs<\/strong><\/td><td><code>https:\/\/llm.yourdomain.com\/sso\/callback<\/code><\/td><\/tr><tr><td><strong>Scopes<\/strong><\/td><td>Select: <code>openid<\/code>, <code>profile<\/code>, <code>email<\/code>, <code>LiteLLM Role<\/code><\/td><\/tr><tr><td><strong>Subject mode<\/strong><\/td><td>Based on the User&#8217;s Username<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/07-authentik-provider-detail.png\" alt=\"Authentik OAuth2 provider detail for LiteLLM\" class=\"wp-image-2095\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/07-authentik-provider-detail.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/07-authentik-provider-detail-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/07-authentik-provider-detail-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/07-authentik-provider-detail-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">The LiteLLM Provider in Authentik showing all OIDC endpoints and the redirect URI.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1280\" height=\"800\" src=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/06-authentik-providers.png\" alt=\"Authentik providers list\" class=\"wp-image-2094\" srcset=\"https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/06-authentik-providers.png 1280w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/06-authentik-providers-300x188.png 300w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/06-authentik-providers-1024x640.png 1024w, https:\/\/cln.io\/blog\/wp-content\/uploads\/2026\/03\/06-authentik-providers-768x480.png 768w\" sizes=\"auto, (max-width: 1280px) 100vw, 1280px\" \/><figcaption class=\"wp-element-caption\">The providers list showing the LiteLLM Provider.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Important:<\/strong> Make sure to add the <code>LiteLLM Role<\/code> scope mapping (from Step 1) to the provider&#8217;s scopes. Without it, the role claim won&#8217;t be included in the token.<\/p>\n\n\n\n<h3 id=\"3-create-an-application\" class=\"wp-block-heading\">3. Create an Application<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Go to <strong>Applications \u2192 Applications \u2192 Create<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Setting<\/th><th>Value<\/th><\/tr><\/thead><tbody><tr><td><strong>Name<\/strong><\/td><td><code>LiteLLM<\/code><\/td><\/tr><tr><td><strong>Slug<\/strong><\/td><td><code>litellm<\/code><\/td><\/tr><tr><td><strong>Provider<\/strong><\/td><td><code>LiteLLM Provider<\/code><\/td><\/tr><tr><td><strong>Launch URL<\/strong><\/td><td><code>https:\/\/llm.yourdomain.com\/ui<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 id=\"part-2-litellm-configuration\" class=\"wp-block-heading\">Part 2: LiteLLM Configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Set these environment variables on your LiteLLM Proxy:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Authentik SSO (Generic OIDC)\nGENERIC_CLIENT_ID=litellm\nGENERIC_CLIENT_SECRET=litellm-client-secret\nGENERIC_AUTHORIZATION_ENDPOINT=https:\/\/auth.yourdomain.com\/application\/o\/authorize\/\nGENERIC_TOKEN_ENDPOINT=https:\/\/auth.yourdomain.com\/application\/o\/token\/\nGENERIC_USERINFO_ENDPOINT=https:\/\/auth.yourdomain.com\/application\/o\/userinfo\/\nGENERIC_SCOPE=openid profile email litellm_role\nGENERIC_USER_ROLE_ATTRIBUTE=litellm_role\nPROXY_BASE_URL=https:\/\/llm.yourdomain.com\nPROXY_LOGOUT_URL=https:\/\/auth.yourdomain.com\/application\/o\/litellm\/end-session\/\nAUTO_REDIRECT_UI_LOGIN_TO_SSO=true<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s what each one does:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Variable<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>GENERIC_CLIENT_ID<\/code> \/ <code>SECRET<\/code><\/td><td>Must match what you set in the Authentik provider<\/td><\/tr><tr><td><code>GENERIC_*_ENDPOINT<\/code><\/td><td>Standard OIDC endpoints &#8211; Authentik shows these on the provider detail page<\/td><\/tr><tr><td><code>GENERIC_SCOPE<\/code><\/td><td>Must include <code>litellm_role<\/code> to request the custom scope<\/td><\/tr><tr><td><code>GENERIC_USER_ROLE_ATTRIBUTE<\/code><\/td><td><strong>The magic.<\/strong> Tells LiteLLM which field in the userinfo response contains the role<\/td><\/tr><tr><td><code>PROXY_BASE_URL<\/code><\/td><td>Used to construct the redirect URI (<code>\/sso\/callback<\/code>)<\/td><\/tr><tr><td><code>PROXY_LOGOUT_URL<\/code><\/td><td>Where to redirect after logout &#8211; use Authentik&#8217;s OIDC end-session endpoint so the user is logged out of both LiteLLM <em>and<\/em> Authentik<\/td><\/tr><tr><td><code>AUTO_REDIRECT_UI_LOGIN_TO_SSO<\/code><\/td><td>Skip the LiteLLM login page entirely &#8211; visiting <code>\/ui<\/code> sends users straight to Authentik<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 id=\"how-the-flow-works\" class=\"wp-block-heading\">How the Flow Works<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>User visits <code>\/ui<\/code> &#8211; with auto-redirect enabled, they&#8217;re sent straight to Authentik (no login page)<\/li>\n\n\n\n<li>LiteLLM redirects to Authentik&#8217;s authorization endpoint with <code>scope=openid profile email litellm_role<\/code><\/li>\n\n\n\n<li>User authenticates on Authentik<\/li>\n\n\n\n<li>Authentik redirects back to <code>\/sso\/callback<\/code> with an authorization code<\/li>\n\n\n\n<li>LiteLLM exchanges the code for a token, then calls the userinfo endpoint<\/li>\n\n\n\n<li>Authentik returns user info including <code>\"litellm_role\": \"proxy_admin\"<\/code><\/li>\n\n\n\n<li>LiteLLM creates the user in its DB with <code>user_role=proxy_admin<\/code><\/li>\n\n\n\n<li>User lands on the full admin dashboard<\/li>\n<\/ol>\n\n\n\n<h2 id=\"bonus-auto-redirect-and-logout\" class=\"wp-block-heading\">Bonus: Auto-Redirect and Logout<\/h2>\n\n\n\n<h3 id=\"skip-the-login-page-with-auto-redirect-ui-login-to-sso\" class=\"wp-block-heading\">Skip the login page with AUTO_REDIRECT_UI_LOGIN_TO_SSO<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">By default, visiting <code>\/ui<\/code> shows LiteLLM&#8217;s login page with a &#8220;Login with SSO&#8221; button. If Authentik is your only auth method, you can skip this page entirely:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">AUTO_REDIRECT_UI_LOGIN_TO_SSO=true<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With this set, navigating to <code>https:\/\/llm.yourdomain.com\/ui<\/code> immediately redirects to Authentik. Users never see the LiteLLM login form &#8211; they go straight to SSO.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note:<\/strong> This also hides the username\/password login. If you need to log in with the master key for debugging, use the API directly with <code>Authorization: Bearer $LITELLM_MASTER_KEY<\/code>.<\/p>\n\n\n\n<h3 id=\"proper-logout-with-proxy-logout-url\" class=\"wp-block-heading\">Proper logout with PROXY_LOGOUT_URL<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Without this, clicking &#8220;Logout&#8221; in LiteLLM only clears the local session &#8211; the user is still authenticated in Authentik. The next time they visit LiteLLM, they&#8217;re silently logged back in (especially annoying with auto-redirect enabled).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Set <code>PROXY_LOGOUT_URL<\/code> to Authentik&#8217;s OIDC end-session endpoint:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">PROXY_LOGOUT_URL=https:\/\/auth.yourdomain.com\/application\/o\/litellm\/end-session\/<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The URL format is <code>https:\/\/&lt;authentik-host&gt;\/application\/o\/&lt;application-slug&gt;\/end-session\/<\/code>. This logs the user out of both LiteLLM and Authentik in one click.<\/p>\n\n\n\n<h2 id=\"gotchas\" class=\"wp-block-heading\">Gotchas<\/h2>\n\n\n\n<h3 id=\"email-validation\" class=\"wp-block-heading\">Email validation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">LiteLLM uses Pydantic to validate the email from the SSO response. Emails with <code>.local<\/code> TLD (like <code>admin@demo.local<\/code>) will be rejected. You have a few options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Use real email domains<\/strong> &#8211; make sure your Authentik users have valid emails (e.g. <code>user@yourdomain.com<\/code>)<\/li>\n\n\n\n<li><strong>Map email to a different field<\/strong> &#8211; set <code>GENERIC_USER_EMAIL_ATTRIBUTE<\/code> to pull from a different claim (e.g. <code>preferred_username<\/code>) that doesn&#8217;t get validated as strictly<\/li>\n\n\n\n<li><strong>Drop email from the scope<\/strong> &#8211; remove <code>email<\/code> from <code>GENERIC_SCOPE<\/code> so Authentik doesn&#8217;t send it at all<\/li>\n\n\n\n<li><strong>Fabricate a valid email in Authentik<\/strong> &#8211; create a scope mapping that generates an email from the username: <code>return {\"email\": request.user.username + \"@yourdomain.com\"}<\/code><\/li>\n<\/ul>\n\n\n\n<h3 id=\"role-is-persisted-on-first-login\" class=\"wp-block-heading\">Role is persisted on first login<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The role from the SSO claim is written to LiteLLM&#8217;s database on the user&#8217;s <strong>first login<\/strong>. If you add the role mapping after a user has already logged in, their old role sticks. Fix it with a one-time API call:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">curl -X POST https:\/\/llm.yourdomain.com\/user\/update \\\n  -H \"Authorization: Bearer $LITELLM_MASTER_KEY\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\"user_id\": \"the-username\", \"user_role\": \"proxy_admin\"}'<\/pre>\n\n\n\n<h3 id=\"self-signed-certificates\" class=\"wp-block-heading\">Self-signed certificates<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re running with self-signed certs (dev\/lab), LiteLLM&#8217;s SSO library (<code>fastapi_sso<\/code>) uses <code>httpx<\/code> which will reject them. You&#8217;ll need to either:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use real certs (recommended for production)<\/li>\n\n\n\n<li>Monkeypatch <code>httpx.AsyncClient<\/code> to default to <code>verify=False<\/code><\/li>\n\n\n\n<li>Ensure <code>auth.yourdomain.com<\/code> resolves to your reverse proxy from inside the LiteLLM container<\/li>\n<\/ul>\n\n\n\n<h2 id=\"docker-compose-example\" class=\"wp-block-heading\">Docker Compose Example<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">services:\n  litellm:\n    image: ghcr.io\/berriai\/litellm:main-stable\n    environment:\n      DATABASE_URL: \"postgresql:\/\/litellm:secret@litellm-db:5432\/litellm\"\n      STORE_MODEL_IN_DB: \"True\"\n      LITELLM_MASTER_KEY: \"sk-your-master-key\"\n      LITELLM_SALT_KEY: \"sk-your-salt-key\"\n      GENERIC_CLIENT_ID: \"litellm\"\n      GENERIC_CLIENT_SECRET: \"your-client-secret\"\n      GENERIC_AUTHORIZATION_ENDPOINT: \"https:\/\/auth.yourdomain.com\/application\/o\/authorize\/\"\n      GENERIC_TOKEN_ENDPOINT: \"https:\/\/auth.yourdomain.com\/application\/o\/token\/\"\n      GENERIC_USERINFO_ENDPOINT: \"https:\/\/auth.yourdomain.com\/application\/o\/userinfo\/\"\n      GENERIC_SCOPE: \"openid profile email litellm_role\"\n      GENERIC_USER_ROLE_ATTRIBUTE: \"litellm_role\"\n      PROXY_BASE_URL: \"https:\/\/llm.yourdomain.com\"\n      PROXY_LOGOUT_URL: \"https:\/\/auth.yourdomain.com\/application\/o\/litellm\/end-session\/\"\n      AUTO_REDIRECT_UI_LOGIN_TO_SSO: \"true\"\n    ports:\n      - \"4000:4000\"\n\n  litellm-db:\n    image: postgres:16-alpine\n    environment:\n      POSTGRES_DB: litellm\n      POSTGRES_USER: litellm\n      POSTGRES_PASSWORD: secret\n    volumes:\n      - litellm_data:\/var\/lib\/postgresql\/data\n\nvolumes:\n  litellm_data:<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Tested with LiteLLM v1.81.14 and Authentik 2025.2.1. The SSO feature is free for up to 5 users as of LiteLLM v1.76.0+.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>This post was written by <a href=\"https:\/\/claude.ai\">Claude<\/a> (claude-opus-4-6), Anthropic&#8217;s AI assistant, with human direction and review.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>LiteLLM is an OpenAI-compatible proxy that lets you route requests to multiple LLM providers through a single API. It has a built-in admin UI with SSO support. Authentik is an open-source identity provider that supports [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2055,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[63,48,26],"tags":[],"class_list":["post-1923","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-authentication","category-security","category-it"],"_links":{"self":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts\/1923","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/comments?post=1923"}],"version-history":[{"count":10,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts\/1923\/revisions"}],"predecessor-version":[{"id":2098,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/posts\/1923\/revisions\/2098"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/media\/2055"}],"wp:attachment":[{"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/media?parent=1923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/categories?post=1923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cln.io\/blog\/wp-json\/wp\/v2\/tags?post=1923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}