diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 12812ae0a..02c06487a 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -362,6 +362,30 @@ MICROSOFT_REDIRECT_URI = PersistentConfig( os.environ.get("MICROSOFT_REDIRECT_URI", ""), ) +GITHUB_CLIENT_ID = PersistentConfig( + "GITHUB_CLIENT_ID", + "oauth.github.client_id", + os.environ.get("GITHUB_CLIENT_ID", ""), +) + +GITHUB_CLIENT_SECRET = PersistentConfig( + "GITHUB_CLIENT_SECRET", + "oauth.github.client_secret", + os.environ.get("GITHUB_CLIENT_SECRET", ""), +) + +GITHUB_CLIENT_SCOPE = PersistentConfig( + "GITHUB_CLIENT_SCOPE", + "oauth.github.scope", + os.environ.get("GITHUB_CLIENT_SCOPE", "user:email"), +) + +GITHUB_CLIENT_REDIRECT_URI = PersistentConfig( + "GITHUB_CLIENT_REDIRECT_URI", + "oauth.github.redirect_uri", + os.environ.get("GITHUB_CLIENT_REDIRECT_URI", ""), +) + OAUTH_CLIENT_ID = PersistentConfig( "OAUTH_CLIENT_ID", "oauth.oidc.client_id", @@ -468,12 +492,20 @@ OAUTH_ALLOWED_DOMAINS = PersistentConfig( def load_oauth_providers(): OAUTH_PROVIDERS.clear() if GOOGLE_CLIENT_ID.value and GOOGLE_CLIENT_SECRET.value: + def google_oauth_register(client): + client.register( + name="google", + client_id=GOOGLE_CLIENT_ID.value, + client_secret=GOOGLE_CLIENT_SECRET.value, + server_metadata_url="https://accounts.google.com/.well-known/openid-configuration", + client_kwargs={ + "scope": GOOGLE_OAUTH_SCOPE.value + }, + redirect_uri=GOOGLE_REDIRECT_URI.value, + ) OAUTH_PROVIDERS["google"] = { - "client_id": GOOGLE_CLIENT_ID.value, - "client_secret": GOOGLE_CLIENT_SECRET.value, - "server_metadata_url": "https://accounts.google.com/.well-known/openid-configuration", - "scope": GOOGLE_OAUTH_SCOPE.value, "redirect_uri": GOOGLE_REDIRECT_URI.value, + "register": google_oauth_register, } if ( @@ -481,13 +513,42 @@ def load_oauth_providers(): and MICROSOFT_CLIENT_SECRET.value and MICROSOFT_CLIENT_TENANT_ID.value ): + def microsoft_oauth_register(client): + client.register( + name="microsoft", + client_id=MICROSOFT_CLIENT_ID.value, + client_secret=MICROSOFT_CLIENT_SECRET.value, + server_metadata_url=f"https://login.microsoftonline.com/{MICROSOFT_CLIENT_TENANT_ID.value}/v2.0/.well-known/openid-configuration", + client_kwargs={ + "scope": MICROSOFT_OAUTH_SCOPE.value, + }, + redirect_uri=MICROSOFT_REDIRECT_URI.value, + ) OAUTH_PROVIDERS["microsoft"] = { - "client_id": MICROSOFT_CLIENT_ID.value, - "client_secret": MICROSOFT_CLIENT_SECRET.value, - "server_metadata_url": f"https://login.microsoftonline.com/{MICROSOFT_CLIENT_TENANT_ID.value}/v2.0/.well-known/openid-configuration", - "scope": MICROSOFT_OAUTH_SCOPE.value, "redirect_uri": MICROSOFT_REDIRECT_URI.value, "picture_url": "https://graph.microsoft.com/v1.0/me/photo/$value", + "register": microsoft_oauth_register, + } + + if GITHUB_CLIENT_ID.value and GITHUB_CLIENT_SECRET.value: + def github_oauth_register(client): + client.register( + name="github", + client_id=GITHUB_CLIENT_ID.value, + client_secret=GITHUB_CLIENT_SECRET.value, + access_token_url="https://github.com/login/oauth/access_token", + authorize_url="https://github.com/login/oauth/authorize", + api_base_url="https://api.github.com", + userinfo_endpoint="https://api.github.com/user", + client_kwargs={ + "scope": GITHUB_CLIENT_SCOPE.value + }, + redirect_uri=GITHUB_CLIENT_REDIRECT_URI.value, + ) + OAUTH_PROVIDERS["github"] = { + "redirect_uri": GITHUB_CLIENT_REDIRECT_URI.value, + "register": github_oauth_register, + "sub_claim": "id", } if ( @@ -495,13 +556,21 @@ def load_oauth_providers(): and OAUTH_CLIENT_SECRET.value and OPENID_PROVIDER_URL.value ): + def oidc_oauth_register(client): + client.register( + name="oidc", + client_id=OAUTH_CLIENT_ID.value, + client_secret=OAUTH_CLIENT_SECRET.value, + server_metadata_url=OPENID_PROVIDER_URL.value, + client_kwargs={ + "scope": OAUTH_SCOPES.value, + }, + redirect_uri=OPENID_REDIRECT_URI.value, + ) OAUTH_PROVIDERS["oidc"] = { - "client_id": OAUTH_CLIENT_ID.value, - "client_secret": OAUTH_CLIENT_SECRET.value, - "server_metadata_url": OPENID_PROVIDER_URL.value, - "scope": OAUTH_SCOPES.value, "name": OAUTH_PROVIDER_NAME.value, "redirect_uri": OPENID_REDIRECT_URI.value, + "register": oidc_oauth_register, } diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 386ea05ca..1ae6d4aa7 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -63,17 +63,8 @@ auth_manager_config.JWT_EXPIRES_IN = JWT_EXPIRES_IN class OAuthManager: def __init__(self): self.oauth = OAuth() - for provider_name, provider_config in OAUTH_PROVIDERS.items(): - self.oauth.register( - name=provider_name, - client_id=provider_config["client_id"], - client_secret=provider_config["client_secret"], - server_metadata_url=provider_config["server_metadata_url"], - client_kwargs={ - "scope": provider_config["scope"], - }, - redirect_uri=provider_config["redirect_uri"], - ) + for _, provider_config in OAUTH_PROVIDERS.items(): + provider_config["register"](self.oauth) def get_client(self, provider_name): return self.oauth.create_client(provider_name) @@ -207,7 +198,7 @@ class OAuthManager: log.warning(f"OAuth callback failed, user data is missing: {token}") raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) - sub = user_data.get("sub") + sub = user_data.get(OAUTH_PROVIDERS[provider].get("sub_claim", "sub")) if not sub: log.warning(f"OAuth callback failed, sub is missing: {user_data}") raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index 00bbe7799..5439baa90 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -374,6 +374,22 @@ {$i18n.t('Continue with {{provider}}', { provider: 'Microsoft' })} {/if} + {#if $config?.oauth?.providers?.github} + + {/if} {#if $config?.oauth?.providers?.oidc}