From 52fa2fcb50d4508518ccd3feb976a9bb2efc8ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= Date: Wed, 25 Feb 2026 17:06:20 +0100 Subject: [PATCH 1/7] feat: enableSingleSignOnSignUp support --- lib/config.ts | 6 +++--- lib/models/oidc.ts | 2 +- lib/types.ts | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index f9b1f33..1d44fef 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -16,6 +16,7 @@ export class AppConfig { allowedCookieDomains: [], skipCookieDomainSecurity: false, enableSingleSignOn: false, + enableSingleSignOnSignUp: false, singleSignOnUrl: '', singleSignOnEmailAttribute: 'email', singleSignOnScopes: ['openid', 'email'], @@ -117,11 +118,10 @@ export class AppConfig { return this.config; } - static async isSignupAllowed(): Promise { + static async isSignupAllowed(sso: boolean=false): Promise { await this.loadConfig(); - const areSignupsAllowed = this.config.auth.allowSignups; - + const areSignupsAllowed = (sso) ? this.config.auth.enableSingleSignOnSignUp : this.config.auth.allowSignups; const areThereAdmins = await UserModel.isThereAnAdmin(); if (areSignupsAllowed || !areThereAdmins) { diff --git a/lib/models/oidc.ts b/lib/models/oidc.ts index 3010aef..f9b7d68 100644 --- a/lib/models/oidc.ts +++ b/lib/models/oidc.ts @@ -169,7 +169,7 @@ export class OidcModel { throw new Error(`Missing user/${emailAttribute}`); } - const isSignupAllowed = await AppConfig.isSignupAllowed(); + const isSignupAllowed = await AppConfig.isSignupAllowed(true); const isThereAnAdmin = await UserModel.isThereAnAdmin(); // Confirm the user exists (or signup if allowed) diff --git a/lib/types.ts b/lib/types.ts index 65961d1..f8805be 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -159,6 +159,8 @@ export interface Config { skipCookieDomainSecurity: boolean; /** If true, single sign-on will be enabled */ enableSingleSignOn: boolean; + /** If true, single sign-on signups will be enabled overriding allowSignups */ + enableSingleSignOnSignUp: boolean; /** The Discovery URL (AKA Issuer) of the identity/single sign-on provider */ singleSignOnUrl: string; /** The attribute to prefer as email of the identity/single sign-on provider */ From d4b197a7c1d9e4897cd07b18452fb2aded23cbd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= Date: Wed, 25 Feb 2026 17:07:29 +0100 Subject: [PATCH 2/7] chore: simplify return statement --- lib/config.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index 1d44fef..444d62f 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -124,11 +124,7 @@ export class AppConfig { const areSignupsAllowed = (sso) ? this.config.auth.enableSingleSignOnSignUp : this.config.auth.allowSignups; const areThereAdmins = await UserModel.isThereAnAdmin(); - if (areSignupsAllowed || !areThereAdmins) { - return true; - } - - return false; + return areSignupsAllowed || !areThereAdmins; } static async isAppEnabled(app: OptionalApp): Promise { From 42eaaf8de77e023f9f1a271ca5fe2a2e3dd93e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= Date: Wed, 25 Feb 2026 17:09:31 +0100 Subject: [PATCH 3/7] chore: linted --- lib/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index 444d62f..892335d 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -118,10 +118,10 @@ export class AppConfig { return this.config; } - static async isSignupAllowed(sso: boolean=false): Promise { + static async isSignupAllowed(sso: boolean = false): Promise { await this.loadConfig(); - const areSignupsAllowed = (sso) ? this.config.auth.enableSingleSignOnSignUp : this.config.auth.allowSignups; + const areSignupsAllowed = sso ? this.config.auth.enableSingleSignOnSignUp : this.config.auth.allowSignups; const areThereAdmins = await UserModel.isThereAnAdmin(); return areSignupsAllowed || !areThereAdmins; From 4cfb22a2c8874d4bc3b1bcc5e848b6860ff70ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= Date: Wed, 25 Feb 2026 17:32:34 +0100 Subject: [PATCH 4/7] feat: verbose error on not enabled SSO sign up --- lib/models/oidc.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/models/oidc.ts b/lib/models/oidc.ts index f9b7d68..6230ac4 100644 --- a/lib/models/oidc.ts +++ b/lib/models/oidc.ts @@ -181,6 +181,10 @@ export class OidcModel { } if (!user) { + // this will allow admin account creation even if SSO signups are disabled following the foregoing logic + if (!config.auth.enableSingleSignOnSignUp) { + throw new Error('Sign up via SSO is not enabled'); + } throw new Error('There was a problem signing up or logging in!'); } From 9ce1cacccef60ebb59fa3477eaad6a5d04a24135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= Date: Wed, 25 Feb 2026 17:53:39 +0100 Subject: [PATCH 5/7] chore: update config key to match others --- lib/config.ts | 4 ++-- lib/models/oidc.ts | 5 +++-- lib/types.ts | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index 892335d..8828e3a 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -16,7 +16,7 @@ export class AppConfig { allowedCookieDomains: [], skipCookieDomainSecurity: false, enableSingleSignOn: false, - enableSingleSignOnSignUp: false, + allowSingleSignOnSignups: false, singleSignOnUrl: '', singleSignOnEmailAttribute: 'email', singleSignOnScopes: ['openid', 'email'], @@ -121,7 +121,7 @@ export class AppConfig { static async isSignupAllowed(sso: boolean = false): Promise { await this.loadConfig(); - const areSignupsAllowed = sso ? this.config.auth.enableSingleSignOnSignUp : this.config.auth.allowSignups; + const areSignupsAllowed = sso ? this.config.auth.allowSingleSignOnSignups : this.config.auth.allowSignups; const areThereAdmins = await UserModel.isThereAnAdmin(); return areSignupsAllowed || !areThereAdmins; diff --git a/lib/models/oidc.ts b/lib/models/oidc.ts index 6230ac4..9ef0fb9 100644 --- a/lib/models/oidc.ts +++ b/lib/models/oidc.ts @@ -182,9 +182,10 @@ export class OidcModel { if (!user) { // this will allow admin account creation even if SSO signups are disabled following the foregoing logic - if (!config.auth.enableSingleSignOnSignUp) { - throw new Error('Sign up via SSO is not enabled'); + if (!config.auth.allowSingleSignOnSignups) { + throw new Error('Sign up via SSO is not allowed'); } + throw new Error('There was a problem signing up or logging in!'); } diff --git a/lib/types.ts b/lib/types.ts index f8805be..d852059 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -159,8 +159,8 @@ export interface Config { skipCookieDomainSecurity: boolean; /** If true, single sign-on will be enabled */ enableSingleSignOn: boolean; - /** If true, single sign-on signups will be enabled overriding allowSignups */ - enableSingleSignOnSignUp: boolean; + /** If true, single sign-on signups will be allowed overriding allowSignups */ + allowSingleSignOnSignups: boolean; /** The Discovery URL (AKA Issuer) of the identity/single sign-on provider */ singleSignOnUrl: string; /** The attribute to prefer as email of the identity/single sign-on provider */ From 436d919ead68cfc622a3e9d8084e9bee7de5d326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= Date: Wed, 25 Feb 2026 17:56:26 +0100 Subject: [PATCH 6/7] chore: add key to config sample --- bewcloud.config.sample.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/bewcloud.config.sample.ts b/bewcloud.config.sample.ts index b2b86c8..f39bbd3 100644 --- a/bewcloud.config.sample.ts +++ b/bewcloud.config.sample.ts @@ -11,6 +11,7 @@ const config: PartialDeep = { // allowedCookieDomains: ['example.com', 'example.net'], // Can be set to allow more than the baseUrl's domain for session cookies // skipCookieDomainSecurity: true, // If true, the cookie domain will not be strictly set and checked against. This skipping slightly reduces security, but is usually necessary for reverse proxies like Cloudflare Tunnel // enableSingleSignOn: false, // If true, single sign-on will be enabled + // allowSingleSignOnSignups: false, // If true, single sign-on signups will be allowed overriding allowSignups // singleSignOnUrl: '', // The Discovery URL (AKA Issuer) of the identity/single sign-on provider // singleSignOnEmailAttribute: 'email', // The attribute to prefer as email of the identity/single sign-on provider // singleSignOnScopes: ['openid', 'email'], // The scopes to request from the identity/single sign-on provider From cc5d6e724a38efee0cd94144022f5df671567287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=81oboda?= <47437867+loboda4450@users.noreply.github.com> Date: Thu, 26 Feb 2026 09:44:09 +0100 Subject: [PATCH 7/7] chore: apply suggestions from code review Co-authored-by: BrunoBernardino Co-authored-by: Bruno Bernardino --- bewcloud.config.sample.ts | 2 +- lib/config.ts | 6 +++--- lib/models/oidc.ts | 7 +++---- lib/types.ts | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/bewcloud.config.sample.ts b/bewcloud.config.sample.ts index f39bbd3..67e44b6 100644 --- a/bewcloud.config.sample.ts +++ b/bewcloud.config.sample.ts @@ -11,7 +11,7 @@ const config: PartialDeep = { // allowedCookieDomains: ['example.com', 'example.net'], // Can be set to allow more than the baseUrl's domain for session cookies // skipCookieDomainSecurity: true, // If true, the cookie domain will not be strictly set and checked against. This skipping slightly reduces security, but is usually necessary for reverse proxies like Cloudflare Tunnel // enableSingleSignOn: false, // If true, single sign-on will be enabled - // allowSingleSignOnSignups: false, // If true, single sign-on signups will be allowed overriding allowSignups + // allowSignupsViaSingleSignOn: false, // If true, signups via single sign-on will be allowed, overriding allowSignups // singleSignOnUrl: '', // The Discovery URL (AKA Issuer) of the identity/single sign-on provider // singleSignOnEmailAttribute: 'email', // The attribute to prefer as email of the identity/single sign-on provider // singleSignOnScopes: ['openid', 'email'], // The scopes to request from the identity/single sign-on provider diff --git a/lib/config.ts b/lib/config.ts index 8828e3a..42c4cc6 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -16,7 +16,7 @@ export class AppConfig { allowedCookieDomains: [], skipCookieDomainSecurity: false, enableSingleSignOn: false, - allowSingleSignOnSignups: false, + allowSignupsViaSingleSignOn: false, singleSignOnUrl: '', singleSignOnEmailAttribute: 'email', singleSignOnScopes: ['openid', 'email'], @@ -118,10 +118,10 @@ export class AppConfig { return this.config; } - static async isSignupAllowed(sso: boolean = false): Promise { + static async isSignupAllowed({ viaSingleSignOn = false }: { viaSingleSignOn?: boolean } = {}): Promise { await this.loadConfig(); - const areSignupsAllowed = sso ? this.config.auth.allowSingleSignOnSignups : this.config.auth.allowSignups; + const areSignupsAllowed = viaSingleSignOn && !this.config.auth.allowSignups ? this.config.auth.allowSingleSignOnSignups : this.config.auth.allowSignups; const areThereAdmins = await UserModel.isThereAnAdmin(); return areSignupsAllowed || !areThereAdmins; diff --git a/lib/models/oidc.ts b/lib/models/oidc.ts index 9ef0fb9..fb09070 100644 --- a/lib/models/oidc.ts +++ b/lib/models/oidc.ts @@ -169,7 +169,7 @@ export class OidcModel { throw new Error(`Missing user/${emailAttribute}`); } - const isSignupAllowed = await AppConfig.isSignupAllowed(true); + const isSignupAllowed = await AppConfig.isSignupAllowed({ viaSingleSignOn: true }); const isThereAnAdmin = await UserModel.isThereAnAdmin(); // Confirm the user exists (or signup if allowed) @@ -181,9 +181,8 @@ export class OidcModel { } if (!user) { - // this will allow admin account creation even if SSO signups are disabled following the foregoing logic - if (!config.auth.allowSingleSignOnSignups) { - throw new Error('Sign up via SSO is not allowed'); + if (!config.auth.allowSignupsViaSingleSignOn) { + throw new Error('Sign up via SSO is not allowed!'); } throw new Error('There was a problem signing up or logging in!'); diff --git a/lib/types.ts b/lib/types.ts index d852059..e05306c 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -159,8 +159,8 @@ export interface Config { skipCookieDomainSecurity: boolean; /** If true, single sign-on will be enabled */ enableSingleSignOn: boolean; - /** If true, single sign-on signups will be allowed overriding allowSignups */ - allowSingleSignOnSignups: boolean; + /** If true, signups via single sign-on will be allowed, overriding allowSignups */ + allowSignupsViaSingleSignOn: boolean; /** The Discovery URL (AKA Issuer) of the identity/single sign-on provider */ singleSignOnUrl: string; /** The attribute to prefer as email of the identity/single sign-on provider */