feat(auth): Add OIDC/OAuth2 login with admin + self-service tiers - #6192
Open
CRASH-Tech wants to merge 5 commits into
Open
feat(auth): Add OIDC/OAuth2 login with admin + self-service tiers#6192CRASH-Tech wants to merge 5 commits into
CRASH-Tech wants to merge 5 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(auth): OIDC/OAuth2 login with admin + self-service tiers
Summary
Adds single sign-on through any OpenID Connect provider (Keycloak, Authentik,
Authelia, Google, Azure AD, Okta, …). It can be configured declaratively via
XUI_OAUTH_*environment variables, from the panel settings UI, or both —env values take precedence and lock the matching UI fields read-only.
A group claim in the ID token maps each caller to one of two tiers:
first user (no per-admin data, so no new rows / migration).
inbound(s) whose remark matches the configured list, and the user lands in a
self-service cabinet showing only their own connection: subscription URL,
share links with protocol/transport badges, QR codes, and traffic/expiry.
How it works
audience and nonce are verified before a session is opened.
client subId live in the session — no DB schema change / migration.
XUI_OAUTH_*(priority) over stored values. An env-pinned field is shown read-only in the UI
with its live value; the client secret is never echoed (only a "configured"
flag). Server-side, env-locked fields cannot be changed through the API. The
enable toggle is auto-on and locked when the issuer + client id come from env.
ClientService.Create(runtime-safe, the LDAP-sync path),so multi-node deployments are handled. It is idempotent and reconciling: on
later logins an existing client is attached to any newly matching inbound (same
subId/limits, no reset).
users, so a new matching inbound reaches them without a re-login. It only
attaches — never deletes or disables.
Configuration
Every knob is available as a
XUI_OAUTH_*env var and as a panel setting:XUI_OAUTH_ISSUER/_CLIENT_ID/_CLIENT_SECRETXUI_OAUTH_REDIRECT_URLXUI_OAUTH_ADMIN_GROUPXUI_OAUTH_USER_GROUPXUI_OAUTH_USER_INBOUND_REMARKXUI_OAUTH_USER_TOTAL_GB/_EXPIRY_DAYS/_LIMIT_IP0= unlimited/neverXUI_OAUTH_SCOPES/_GROUPS_CLAIM/_USERNAME_CLAIMopenid,profile,email,groups/groups/emailChanges
internal/config/oauth.go;internal/util/oauth/(go-oidc/oauth2wrapper: discovery, auth URL, code exchange, claim extraction); routes
GET /oauth/login,/oauth/callback,/getOAuthEnable,/cabinet/,/cabinet/data; session role/subid/flow helpers;OAuthProvisionService(provision + reconcile) and
OAuthSyncJob; role gating incheckLogin.Settings:
Oauth*fields onAllSetting,HasOauthClientSecret+OauthEnvLockedonAllSettingView,GetEffectiveOAuthConfig/OAuthEnvLocks/OAuthEnabledEffective/enforceOauthEnvLocks. The OIDCprovider is cached by a config signature so UI edits apply without a restart.
cabinetbundle reusing the subscription page's link/QR components; an "OIDC"section in Settings mirroring LDAP, with env-pinned fields disabled.
github.com/coreos/go-oidc/v3,golang.org/x/oauth2.endpoints.tsXUI_OAUTH_*documented in all 7 README translations;a commented example in
docker-compose.yml.Testing
JWKS + signed ID token, incl. nonce/audience rejection); role mapping;
provisioning (create/reuse, multi-remark, attach-on-new-inbound); batch
reconcile; effective-config env precedence, env locks, enable resolution and
the server-side lock enforcement; a regression test for callback host
resolution (see notes).
go build ./...,golangci-lint(0 issues), gofumpt, route-registry contract— all green.
Notes
Hostheader (with port) produced amalformed
@[host:port]:443URL; the callback now uses the sub server's ownhost resolution.
SubPage and cabinet — such links are too large to scan; use the subscription QR.
user pool (no schema marker), so a manually-added client on such an inbound is
also mirrored across the pool. A
Group/Commentmarker could scope this morestrictly if desired.