mirror of
https://github.com/Eugeny/tabby-web.git
synced 2026-08-16 22:36:02 +01:00
feat: add generic OIDC provider for self-hosted identity providers
Adds support for any OpenID Connect compliant identity provider: - Authentik - Authelia - Keycloak - Okta - Any other OIDC provider Configuration via environment variables: - SOCIAL_AUTH_OIDC_OIDC_ENDPOINT: Discovery endpoint - SOCIAL_AUTH_OIDC_KEY: Client ID - SOCIAL_AUTH_OIDC_SECRET: Client secret - SOCIAL_AUTH_OIDC_NAME: Optional custom button text Closes #140 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
20
README.md
20
README.md
@@ -52,9 +52,29 @@ Only providers with credentials configured will appear as login options. Set the
|
|||||||
| Google | `SOCIAL_AUTH_GOOGLE_OAUTH2_KEY`, `SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET` |
|
| Google | `SOCIAL_AUTH_GOOGLE_OAUTH2_KEY`, `SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET` |
|
||||||
| Microsoft | `SOCIAL_AUTH_MICROSOFT_GRAPH_KEY`, `SOCIAL_AUTH_MICROSOFT_GRAPH_SECRET` |
|
| Microsoft | `SOCIAL_AUTH_MICROSOFT_GRAPH_KEY`, `SOCIAL_AUTH_MICROSOFT_GRAPH_SECRET` |
|
||||||
| Auth0 | `SOCIAL_AUTH_AUTH0_DOMAIN`, `SOCIAL_AUTH_AUTH0_KEY`, `SOCIAL_AUTH_AUTH0_SECRET` |
|
| Auth0 | `SOCIAL_AUTH_AUTH0_DOMAIN`, `SOCIAL_AUTH_AUTH0_KEY`, `SOCIAL_AUTH_AUTH0_SECRET` |
|
||||||
|
| Generic OIDC | `SOCIAL_AUTH_OIDC_OIDC_ENDPOINT`, `SOCIAL_AUTH_OIDC_KEY`, `SOCIAL_AUTH_OIDC_SECRET` |
|
||||||
|
|
||||||
For Auth0, set the callback URL to: `https://your-domain/api/1/auth/social/complete/auth0/`
|
For Auth0, set the callback URL to: `https://your-domain/api/1/auth/social/complete/auth0/`
|
||||||
|
|
||||||
|
### Generic OIDC Provider
|
||||||
|
|
||||||
|
The generic OIDC provider works with any OpenID Connect compliant identity provider, including:
|
||||||
|
- **Authentik** - Self-hosted identity provider
|
||||||
|
- **Authelia** - Self-hosted authentication server
|
||||||
|
- **Keycloak** - Open source identity management
|
||||||
|
- **Okta** - Enterprise identity platform
|
||||||
|
- And any other OIDC-compliant provider
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
- `SOCIAL_AUTH_OIDC_OIDC_ENDPOINT`: The OIDC discovery endpoint (e.g., `https://authentik.example.com/application/o/<app-slug>/`)
|
||||||
|
- `SOCIAL_AUTH_OIDC_KEY`: Client ID from your identity provider
|
||||||
|
- `SOCIAL_AUTH_OIDC_SECRET`: Client secret from your identity provider
|
||||||
|
- `SOCIAL_AUTH_OIDC_NAME` (optional): Custom button text (default: "SSO")
|
||||||
|
|
||||||
|
Set the callback URL to: `https://your-domain/api/1/auth/social/complete/oidc/`
|
||||||
|
|
||||||
|
**Note on MFA:** Multi-factor authentication is handled by your identity provider. Enable MFA in Authentik, Authelia, or your chosen provider to require 2FA for Tabby Web logins.
|
||||||
|
|
||||||
## Adding Tabby app versions
|
## Adding Tabby app versions
|
||||||
|
|
||||||
* `docker-compose run tabby /manage.sh add_version 1.0.163`
|
* `docker-compose run tabby /manage.sh add_version 1.0.163`
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ PROVIDER_CONFIG = {
|
|||||||
'cls': 'btn-dark',
|
'cls': 'btn-dark',
|
||||||
'env_prefix': 'SOCIAL_AUTH_AUTH0',
|
'env_prefix': 'SOCIAL_AUTH_AUTH0',
|
||||||
},
|
},
|
||||||
|
'oidc': {
|
||||||
|
'name': 'SSO', # Generic name, can be overridden via SOCIAL_AUTH_OIDC_NAME
|
||||||
|
'icon': 'openid', # OpenID icon
|
||||||
|
'cls': 'btn-info',
|
||||||
|
'env_prefix': 'SOCIAL_AUTH_OIDC',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -48,9 +54,19 @@ def is_provider_configured(env_prefix: str) -> bool:
|
|||||||
if env_prefix == 'SOCIAL_AUTH_AUTH0':
|
if env_prefix == 'SOCIAL_AUTH_AUTH0':
|
||||||
domain = getattr(settings, f'{env_prefix}_DOMAIN', None)
|
domain = getattr(settings, f'{env_prefix}_DOMAIN', None)
|
||||||
return bool(key and secret and domain)
|
return bool(key and secret and domain)
|
||||||
|
# For generic OIDC, also need OIDC_ENDPOINT
|
||||||
|
if env_prefix == 'SOCIAL_AUTH_OIDC':
|
||||||
|
endpoint = getattr(settings, f'{env_prefix}_OIDC_ENDPOINT', None)
|
||||||
|
return bool(key and secret and endpoint)
|
||||||
return bool(key and secret)
|
return bool(key and secret)
|
||||||
|
|
||||||
|
|
||||||
|
def get_provider_display_name(env_prefix: str, default_name: str) -> str:
|
||||||
|
"""Get custom display name for a provider, if configured."""
|
||||||
|
custom_name = getattr(settings, f'{env_prefix}_NAME', None)
|
||||||
|
return custom_name if custom_name else default_name
|
||||||
|
|
||||||
|
|
||||||
class LogoutView(APIView):
|
class LogoutView(APIView):
|
||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
logout(request)
|
logout(request)
|
||||||
@@ -66,7 +82,9 @@ class ProvidersView(APIView):
|
|||||||
if is_provider_configured(config['env_prefix']):
|
if is_provider_configured(config['env_prefix']):
|
||||||
providers.append({
|
providers.append({
|
||||||
'id': provider_id,
|
'id': provider_id,
|
||||||
'name': config['name'],
|
'name': get_provider_display_name(
|
||||||
|
config['env_prefix'], config['name']
|
||||||
|
),
|
||||||
'icon': config['icon'],
|
'icon': config['icon'],
|
||||||
'cls': config['cls'],
|
'cls': config['cls'],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ AUTHENTICATION_BACKENDS = (
|
|||||||
"social_core.backends.microsoft.MicrosoftOAuth2",
|
"social_core.backends.microsoft.MicrosoftOAuth2",
|
||||||
"social_core.backends.google.GoogleOAuth2",
|
"social_core.backends.google.GoogleOAuth2",
|
||||||
"social_core.backends.auth0.Auth0OAuth2",
|
"social_core.backends.auth0.Auth0OAuth2",
|
||||||
|
"social_core.backends.open_id_connect.OpenIdConnectAuth",
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -188,6 +189,10 @@ for key in [
|
|||||||
"SOCIAL_AUTH_AUTH0_DOMAIN",
|
"SOCIAL_AUTH_AUTH0_DOMAIN",
|
||||||
"SOCIAL_AUTH_AUTH0_KEY",
|
"SOCIAL_AUTH_AUTH0_KEY",
|
||||||
"SOCIAL_AUTH_AUTH0_SECRET",
|
"SOCIAL_AUTH_AUTH0_SECRET",
|
||||||
|
"SOCIAL_AUTH_OIDC_OIDC_ENDPOINT",
|
||||||
|
"SOCIAL_AUTH_OIDC_KEY",
|
||||||
|
"SOCIAL_AUTH_OIDC_SECRET",
|
||||||
|
"SOCIAL_AUTH_OIDC_NAME",
|
||||||
"CONNECTION_GATEWAY_AUTH_CA",
|
"CONNECTION_GATEWAY_AUTH_CA",
|
||||||
"CONNECTION_GATEWAY_AUTH_CERTIFICATE",
|
"CONNECTION_GATEWAY_AUTH_CERTIFICATE",
|
||||||
"CONNECTION_GATEWAY_AUTH_KEY",
|
"CONNECTION_GATEWAY_AUTH_KEY",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component } from '@angular/core'
|
|||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { LoginService, CommonService } from 'src/common'
|
import { LoginService, CommonService } from 'src/common'
|
||||||
|
|
||||||
import { faGithub, faGitlab, faGoogle, faMicrosoft, IconDefinition } from '@fortawesome/free-brands-svg-icons'
|
import { faGithub, faGitlab, faGoogle, faMicrosoft, faOpenid, IconDefinition } from '@fortawesome/free-brands-svg-icons'
|
||||||
import { faKey } from '@fortawesome/free-solid-svg-icons'
|
import { faKey } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
interface Provider {
|
interface Provider {
|
||||||
@@ -18,6 +18,7 @@ const iconMap: Record<string, IconDefinition> = {
|
|||||||
gitlab: faGitlab,
|
gitlab: faGitlab,
|
||||||
google: faGoogle,
|
google: faGoogle,
|
||||||
microsoft: faMicrosoft,
|
microsoft: faMicrosoft,
|
||||||
|
openid: faOpenid, // Used for generic OIDC providers (Authentik, Authelia, Keycloak, etc.)
|
||||||
key: faKey, // Used for Auth0 and other providers without brand icons
|
key: faKey, // Used for Auth0 and other providers without brand icons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user