Revamp OIDC auth: remove Passport wrapper, add schema-driven settings UI

- Remove Passport.js wrapper from OIDC auth, use openid-client directly
- Add schema-driven OIDC settings UI (OidcSettingsSchema.js drives form rendering)
- Add group mapping with KeyValueEditor (explicit mapping or legacy direct name match)
- Add scopes configuration (authOpenIDScopes)
- Add verified email enforcement option (authOpenIDRequireVerifiedEmail)
- Fix group claim validation rejecting URN-style claims (#4744)
- Add auto-discover endpoint for OIDC provider configuration
- Store oidcIdToken in sessions table instead of cookie
- Add AuthError class for structured error handling in auth flows
- Migration v2.33.0 adds oidcIdToken column and new settings fields
This commit is contained in:
Denis Arnst 2026-02-05 17:54:59 +01:00
parent fe13456a2b
commit 33bee70a12
No known key found for this signature in database
GPG key ID: D5866C58940197BF
16 changed files with 1554 additions and 571 deletions

View file

@ -82,6 +82,9 @@ class ServerSettings {
this.authOpenIDGroupClaim = ''
this.authOpenIDAdvancedPermsClaim = ''
this.authOpenIDSubfolderForRedirectURLs = undefined
this.authOpenIDScopes = 'openid profile email'
this.authOpenIDGroupMap = {}
this.authOpenIDRequireVerifiedEmail = false
if (settings) {
this.construct(settings)
@ -146,6 +149,9 @@ class ServerSettings {
this.authOpenIDGroupClaim = settings.authOpenIDGroupClaim || ''
this.authOpenIDAdvancedPermsClaim = settings.authOpenIDAdvancedPermsClaim || ''
this.authOpenIDSubfolderForRedirectURLs = settings.authOpenIDSubfolderForRedirectURLs
this.authOpenIDScopes = settings.authOpenIDScopes || 'openid profile email'
this.authOpenIDGroupMap = settings.authOpenIDGroupMap || {}
this.authOpenIDRequireVerifiedEmail = !!settings.authOpenIDRequireVerifiedEmail
if (!Array.isArray(this.authActiveAuthMethods)) {
this.authActiveAuthMethods = ['local']
@ -255,7 +261,10 @@ class ServerSettings {
authOpenIDMobileRedirectURIs: this.authOpenIDMobileRedirectURIs, // Do not return to client
authOpenIDGroupClaim: this.authOpenIDGroupClaim, // Do not return to client
authOpenIDAdvancedPermsClaim: this.authOpenIDAdvancedPermsClaim, // Do not return to client
authOpenIDSubfolderForRedirectURLs: this.authOpenIDSubfolderForRedirectURLs
authOpenIDSubfolderForRedirectURLs: this.authOpenIDSubfolderForRedirectURLs,
authOpenIDScopes: this.authOpenIDScopes,
authOpenIDGroupMap: this.authOpenIDGroupMap,
authOpenIDRequireVerifiedEmail: this.authOpenIDRequireVerifiedEmail
}
}
@ -267,6 +276,9 @@ class ServerSettings {
delete json.authOpenIDMobileRedirectURIs
delete json.authOpenIDGroupClaim
delete json.authOpenIDAdvancedPermsClaim
delete json.authOpenIDScopes
delete json.authOpenIDGroupMap
delete json.authOpenIDRequireVerifiedEmail
return json
}
@ -281,29 +293,41 @@ class ServerSettings {
return this.authOpenIDIssuerURL && this.authOpenIDAuthorizationURL && this.authOpenIDTokenURL && this.authOpenIDUserInfoURL && this.authOpenIDJwksURL && this.authOpenIDClientID && this.authOpenIDClientSecret && this.authOpenIDTokenSigningAlgorithm
}
get authenticationSettings() {
/**
* All OIDC-related setting keys (values only, for admin API)
*/
get openIDSettingsValues() {
return {
authLoginCustomMessage: this.authLoginCustomMessage,
authActiveAuthMethods: this.authActiveAuthMethods,
authOpenIDIssuerURL: this.authOpenIDIssuerURL,
authOpenIDAuthorizationURL: this.authOpenIDAuthorizationURL,
authOpenIDTokenURL: this.authOpenIDTokenURL,
authOpenIDUserInfoURL: this.authOpenIDUserInfoURL,
authOpenIDJwksURL: this.authOpenIDJwksURL,
authOpenIDLogoutURL: this.authOpenIDLogoutURL,
authOpenIDClientID: this.authOpenIDClientID, // Do not return to client
authOpenIDClientSecret: this.authOpenIDClientSecret, // Do not return to client
authOpenIDClientID: this.authOpenIDClientID,
authOpenIDClientSecret: this.authOpenIDClientSecret,
authOpenIDTokenSigningAlgorithm: this.authOpenIDTokenSigningAlgorithm,
authOpenIDButtonText: this.authOpenIDButtonText,
authOpenIDAutoLaunch: this.authOpenIDAutoLaunch,
authOpenIDAutoRegister: this.authOpenIDAutoRegister,
authOpenIDMatchExistingBy: this.authOpenIDMatchExistingBy,
authOpenIDMobileRedirectURIs: this.authOpenIDMobileRedirectURIs, // Do not return to client
authOpenIDGroupClaim: this.authOpenIDGroupClaim, // Do not return to client
authOpenIDAdvancedPermsClaim: this.authOpenIDAdvancedPermsClaim, // Do not return to client
authOpenIDMobileRedirectURIs: this.authOpenIDMobileRedirectURIs,
authOpenIDGroupClaim: this.authOpenIDGroupClaim,
authOpenIDAdvancedPermsClaim: this.authOpenIDAdvancedPermsClaim,
authOpenIDSubfolderForRedirectURLs: this.authOpenIDSubfolderForRedirectURLs,
authOpenIDScopes: this.authOpenIDScopes,
authOpenIDGroupMap: this.authOpenIDGroupMap,
authOpenIDRequireVerifiedEmail: this.authOpenIDRequireVerifiedEmail
}
}
authOpenIDSamplePermissions: User.getSampleAbsPermissions()
get authenticationSettings() {
return {
authLoginCustomMessage: this.authLoginCustomMessage,
authActiveAuthMethods: this.authActiveAuthMethods,
openIDSettings: {
values: this.openIDSettingsValues
}
}
}