2024-05-24 12:18:11 -04:00
|
|
|
const passport = require('passport');
|
2023-08-24 21:59:11 +02:00
|
|
|
const session = require('express-session');
|
2025-08-16 14:49:03 -04:00
|
|
|
const { CacheKeys } = require('librechat-data-provider');
|
🔒 fix: Secure Cookie Localhost Bypass and OpenID Token Selection in AuthService (#11782)
* 🔒 fix: Secure Cookie Localhost Bypass and OpenID Token Selection in AuthService
Two independent bugs in `api/server/services/AuthService.js` cause complete
authentication failure when using `OPENID_REUSE_TOKENS=true` with Microsoft
Entra ID (or Auth0) on `http://localhost` with `NODE_ENV=production`:
Bug 1: `secure: isProduction` prevents auth cookies on localhost
PR #11518 introduced `shouldUseSecureCookie()` in `socialLogins.js` to handle
the case where `NODE_ENV=production` but the server runs on `http://localhost`.
However, `AuthService.js` was not updated — it still used `secure: isProduction`
in 6 cookie locations across `setAuthTokens()` and `setOpenIDAuthTokens()`.
The `token_provider` cookie being dropped is critical: without it,
`requireJwtAuth` middleware defaults to the `jwt` strategy instead of
`openidJwt`, causing all authenticated requests to return 401.
Bug 2: `setOpenIDAuthTokens()` returns `access_token` instead of `id_token`
The `openIdJwtStrategy` validates the Bearer token via JWKS. For Entra ID
without `OPENID_AUDIENCE`, the `access_token` is a Microsoft Graph API token
(opaque or signed for a different audience), which fails JWKS validation.
The `id_token` is always a standard JWT signed by the IdP's JWKS keys with
the app's `client_id` as audience — which is what the strategy expects.
This is the same root cause as issue #8796 (Auth0 encrypted access tokens).
Changes:
- Consolidate `shouldUseSecureCookie()` into `packages/api/src/oauth/csrf.ts`
as a shared, typed utility exported from `@librechat/api`, replacing the
duplicate definitions in `AuthService.js` and `socialLogins.js`
- Move `isProduction` check inside the function body so it is evaluated at
call time rather than module load time
- Fix `packages/api/src/oauth/csrf.ts` which also used bare
`secure: isProduction` for CSRF and session cookies (same localhost bug)
- Return `tokenset.id_token || tokenset.access_token` from
`setOpenIDAuthTokens()` so JWKS validation works with standard OIDC
providers; falls back to `access_token` for backward compatibility
- Add 15 tests for `shouldUseSecureCookie()` covering production/dev modes,
localhost variants, edge cases, and a documented IPv6 bracket limitation
- Add 13 tests for `setOpenIDAuthTokens()` covering token selection,
session storage, cookie secure flag delegation, and edge cases
Refs: #8796, #11518, #11236, #9931
* chore: Adjust Import Order and Type Definitions in AgentPanel Component
- Reordered imports in `AgentPanel.tsx` for better organization and clarity.
- Updated type imports to ensure proper usage of `FieldNamesMarkedBoolean` and `TranslationKeys`.
- Removed redundant imports to streamline the codebase.
2026-02-13 10:35:51 -05:00
|
|
|
const { isEnabled, shouldUseSecureCookie } = require('@librechat/api');
|
2026-01-19 12:01:43 -05:00
|
|
|
const { logger, DEFAULT_SESSION_EXPIRY } = require('@librechat/data-schemas');
|
2023-08-24 21:59:11 +02:00
|
|
|
const {
|
2025-08-16 14:49:03 -04:00
|
|
|
openIdJwtLogin,
|
|
|
|
|
facebookLogin,
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
facebookAdminLogin,
|
2025-08-16 14:49:03 -04:00
|
|
|
discordLogin,
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
discordAdminLogin,
|
2024-05-24 12:18:11 -04:00
|
|
|
setupOpenId,
|
2023-08-24 21:59:11 +02:00
|
|
|
googleLogin,
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
googleAdminLogin,
|
2023-08-24 21:59:11 +02:00
|
|
|
githubLogin,
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
githubAdminLogin,
|
2025-01-31 15:49:09 +01:00
|
|
|
appleLogin,
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
appleAdminLogin,
|
2025-05-30 00:00:58 +09:00
|
|
|
setupSaml,
|
2024-05-24 12:18:11 -04:00
|
|
|
} = require('~/strategies');
|
2025-07-15 16:24:31 -06:00
|
|
|
const { getLogStores } = require('~/cache');
|
2025-08-16 14:49:03 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configures OpenID Connect for the application.
|
|
|
|
|
* @param {Express.Application} app - The Express application instance.
|
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
|
*/
|
|
|
|
|
async function configureOpenId(app) {
|
|
|
|
|
logger.info('Configuring OpenID Connect...');
|
2026-01-19 12:01:43 -05:00
|
|
|
const sessionExpiry = Number(process.env.SESSION_EXPIRY) || DEFAULT_SESSION_EXPIRY;
|
2025-08-16 14:49:03 -04:00
|
|
|
const sessionOptions = {
|
|
|
|
|
secret: process.env.OPENID_SESSION_SECRET,
|
|
|
|
|
resave: false,
|
|
|
|
|
saveUninitialized: false,
|
|
|
|
|
store: getLogStores(CacheKeys.OPENID_SESSION),
|
2026-01-19 12:01:43 -05:00
|
|
|
cookie: {
|
|
|
|
|
maxAge: sessionExpiry,
|
2026-01-26 17:28:50 +01:00
|
|
|
secure: shouldUseSecureCookie(),
|
2026-01-19 12:01:43 -05:00
|
|
|
},
|
2025-08-16 14:49:03 -04:00
|
|
|
};
|
|
|
|
|
app.use(session(sessionOptions));
|
|
|
|
|
app.use(passport.session());
|
|
|
|
|
|
|
|
|
|
const config = await setupOpenId();
|
|
|
|
|
if (!config) {
|
|
|
|
|
logger.error('OpenID Connect configuration failed - strategy not registered.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isEnabled(process.env.OPENID_REUSE_TOKENS)) {
|
|
|
|
|
logger.info('OpenID token reuse is enabled.');
|
|
|
|
|
passport.use('openidJwt', openIdJwtLogin(config));
|
|
|
|
|
}
|
|
|
|
|
logger.info('OpenID Connect configured successfully.');
|
|
|
|
|
}
|
2023-08-24 21:59:11 +02:00
|
|
|
|
2024-01-11 11:37:54 -05:00
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param {Express.Application} app
|
|
|
|
|
*/
|
2025-05-22 14:19:24 +02:00
|
|
|
const configureSocialLogins = async (app) => {
|
2025-03-21 14:14:45 -04:00
|
|
|
logger.info('Configuring social logins...');
|
|
|
|
|
|
2023-08-24 21:59:11 +02:00
|
|
|
if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
|
|
|
|
|
passport.use(googleLogin());
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
passport.use('googleAdmin', googleAdminLogin());
|
2023-08-24 21:59:11 +02:00
|
|
|
}
|
|
|
|
|
if (process.env.FACEBOOK_CLIENT_ID && process.env.FACEBOOK_CLIENT_SECRET) {
|
|
|
|
|
passport.use(facebookLogin());
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
passport.use('facebookAdmin', facebookAdminLogin());
|
2023-08-24 21:59:11 +02:00
|
|
|
}
|
|
|
|
|
if (process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET) {
|
|
|
|
|
passport.use(githubLogin());
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
passport.use('githubAdmin', githubAdminLogin());
|
2023-08-24 21:59:11 +02:00
|
|
|
}
|
|
|
|
|
if (process.env.DISCORD_CLIENT_ID && process.env.DISCORD_CLIENT_SECRET) {
|
|
|
|
|
passport.use(discordLogin());
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
passport.use('discordAdmin', discordAdminLogin());
|
2025-01-31 15:49:09 +01:00
|
|
|
}
|
|
|
|
|
if (process.env.APPLE_CLIENT_ID && process.env.APPLE_PRIVATE_KEY_PATH) {
|
|
|
|
|
passport.use(appleLogin());
|
🔐 feat: Admin Auth Support for SAML and Social OAuth Providers (#12472)
* refactor: Add existingUsersOnly support to social and SAML auth callbacks
- Add `existingUsersOnly` option to the `socialLogin` handler factory to
reject unknown users instead of creating new accounts
- Refactor SAML strategy callback into `createSamlCallback(existingUsersOnly)`
factory function, mirroring the OpenID `createOpenIDCallback` pattern
- Extract shared SAML config into `getBaseSamlConfig()` helper
- Register `samlAdmin` passport strategy with `existingUsersOnly: true` and
admin-specific callback URL, called automatically from `setupSaml()`
* feat: Register admin OAuth strategy variants for all social providers
- Add admin strategy exports to Google, GitHub, Discord, Facebook, and
Apple strategy files with admin callback URLs and existingUsersOnly
- Extract provider configs into reusable helpers to avoid duplication
between regular and admin strategy constructors
- Re-export all admin strategy factories from strategies/index.js
- Register admin passport strategies (googleAdmin, githubAdmin, etc.)
alongside regular ones in socialLogins.js when env vars are present
* feat: Add admin auth routes for SAML and social OAuth providers
- Add initiation and callback routes for SAML, Google, GitHub, Discord,
Facebook, and Apple to the admin auth router
- Each provider follows the exchange code + PKCE pattern established by
OpenID admin auth: store PKCE challenge on initiation, retrieve on
callback, generate exchange code for the admin panel
- SAML and Apple use POST callbacks with state extracted from
req.body.RelayState and req.body.state respectively
- Extract storePkceChallenge(), retrievePkceChallenge(), and
generateState() helpers; refactor existing OpenID routes to use them
- All callback chains enforce requireAdminAccess, setBalanceConfig,
checkDomainAllowed, and the shared createOAuthHandler
- No changes needed to the generic POST /oauth/exchange endpoint
* fix: Update SAML strategy test to handle dual strategy registration
setupSaml() now registers both 'saml' and 'samlAdmin' strategies,
causing the SamlStrategy mock to be called twice. The verifyCallback
variable was getting overwritten with the admin callback (which has
existingUsersOnly: true), making all new-user tests fail.
Fix: capture only the first callback per setupSaml() call and reset
between tests.
* fix: Address review findings for admin OAuth strategy changes
- Fix existingUsersOnly rejection in socialLogin.js to use
cb(null, false, { message }) instead of cb(error), ensuring
passport's failureRedirect fires correctly for admin flows
- Consolidate duplicate require() calls in strategies/index.js by
destructuring admin exports from the already-imported default export
- Pass pre-parsed baseConfig to setupSamlAdmin() to avoid redundant
certificate file I/O at startup
- Extract getGoogleConfig() helper in googleStrategy.js for consistency
with all other provider strategy files
- Replace randomState() (openid-client) with generateState() (crypto)
in the OpenID admin route for consistency with all other providers,
and remove the now-unused openid-client import
* Reorder import statements in auth.js
2026-03-30 22:49:44 -04:00
|
|
|
passport.use('appleAdmin', appleAdminLogin());
|
2023-08-24 21:59:11 +02:00
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
process.env.OPENID_CLIENT_ID &&
|
|
|
|
|
process.env.OPENID_CLIENT_SECRET &&
|
|
|
|
|
process.env.OPENID_ISSUER &&
|
|
|
|
|
process.env.OPENID_SCOPE &&
|
|
|
|
|
process.env.OPENID_SESSION_SECRET
|
|
|
|
|
) {
|
2025-08-16 14:49:03 -04:00
|
|
|
await configureOpenId(app);
|
2023-08-24 21:59:11 +02:00
|
|
|
}
|
2025-05-30 00:00:58 +09:00
|
|
|
if (
|
|
|
|
|
process.env.SAML_ENTRY_POINT &&
|
|
|
|
|
process.env.SAML_ISSUER &&
|
|
|
|
|
process.env.SAML_CERT &&
|
|
|
|
|
process.env.SAML_SESSION_SECRET
|
|
|
|
|
) {
|
|
|
|
|
logger.info('Configuring SAML Connect...');
|
2026-01-19 12:01:43 -05:00
|
|
|
const sessionExpiry = Number(process.env.SESSION_EXPIRY) || DEFAULT_SESSION_EXPIRY;
|
2025-05-30 00:00:58 +09:00
|
|
|
const sessionOptions = {
|
|
|
|
|
secret: process.env.SAML_SESSION_SECRET,
|
|
|
|
|
resave: false,
|
|
|
|
|
saveUninitialized: false,
|
2025-07-15 16:24:31 -06:00
|
|
|
store: getLogStores(CacheKeys.SAML_SESSION),
|
2026-01-19 12:01:43 -05:00
|
|
|
cookie: {
|
|
|
|
|
maxAge: sessionExpiry,
|
2026-01-26 17:28:50 +01:00
|
|
|
secure: shouldUseSecureCookie(),
|
2026-01-19 12:01:43 -05:00
|
|
|
},
|
2025-05-30 00:00:58 +09:00
|
|
|
};
|
|
|
|
|
app.use(session(sessionOptions));
|
|
|
|
|
app.use(passport.session());
|
|
|
|
|
setupSaml();
|
|
|
|
|
|
|
|
|
|
logger.info('SAML Connect configured.');
|
|
|
|
|
}
|
2023-08-24 21:59:11 +02:00
|
|
|
};
|
|
|
|
|
|
2025-03-21 14:14:45 -04:00
|
|
|
module.exports = configureSocialLogins;
|