From 2f353089ad5f816e06065b762ff1871626f03855 Mon Sep 17 00:00:00 2001
From: Kuba <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 10 Apr 2026 12:25:00 +0200
Subject: [PATCH 1/7] clear error on enabling "any"
---
web/src/pages/CERulePage/CERulePage.tsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/web/src/pages/CERulePage/CERulePage.tsx b/web/src/pages/CERulePage/CERulePage.tsx
index 84affcf98..a7d4703af 100644
--- a/web/src/pages/CERulePage/CERulePage.tsx
+++ b/web/src/pages/CERulePage/CERulePage.tsx
@@ -828,6 +828,7 @@ const Content = ({ rule: initialRule, tab }: Props) => {
)}
@@ -856,6 +857,7 @@ const Content = ({ rule: initialRule, tab }: Props) => {
)}
From 3c7216b1e7a19e59be58363a0e56a24e7d356803 Mon Sep 17 00:00:00 2001
From: Kuba <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 10 Apr 2026 13:31:29 +0200
Subject: [PATCH 2/7] add translations
---
web/messages/en/openid.json | 6 ++++++
.../AddExternalOpenIdDirectoryStep.tsx | 2 +-
.../AddExternalOpenIdValidationStep.tsx | 16 ++++++----------
3 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/web/messages/en/openid.json b/web/messages/en/openid.json
index c7033c4df..8c673f46d 100644
--- a/web/messages/en/openid.json
+++ b/web/messages/en/openid.json
@@ -62,6 +62,12 @@
"settings_openid_provider_delete_confirm_body": "Are you sure you want to delete this external identity provider? This action cannot be undone.",
"settings_openid_provider_delete_success": "External identity provider deleted",
"settings_openid_provider_delete_failed": "Failed to delete external identity provider",
+ "settings_openid_provider_validation_success_title": "External ID provider successfully added.",
+ "settings_openid_provider_validation_success_body": "The connection to the external identity provider has been successfully verified.",
+ "settings_openid_provider_validation_success_detail": "The connection to your external identity provider is now verified. Your users can now log in using this provider for a faster and more convenient authentication experience.",
+ "settings_openid_provider_validation_failure_title": "Connection test failed.",
+ "settings_openid_provider_validation_failure_body": "The provider was saved but the connection to the directory synchronization API could not be verified. Go back to fix the configuration, or finish to keep the provider without directory sync.",
+ "settings_openid_provider_validation_failure_error": "Error: {message}",
"openid_consent_title": "{name} would like to",
"openid_consent_scope_openid": "Use OpenID.",
"openid_consent_scope_profile": "Know basic information from your profile.",
diff --git a/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdDirectoryStep/AddExternalOpenIdDirectoryStep.tsx b/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdDirectoryStep/AddExternalOpenIdDirectoryStep.tsx
index 9c1ad1c66..f30f33204 100644
--- a/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdDirectoryStep/AddExternalOpenIdDirectoryStep.tsx
+++ b/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdDirectoryStep/AddExternalOpenIdDirectoryStep.tsx
@@ -47,7 +47,7 @@ export const AddExternalOpenIdDirectoryStep = () => {
const state = useAddExternalOpenIdStore.getState();
const providerState = state.providerState;
const provider = state.provider;
- const submitValues = { ...cloneDeep(providerState), value, kind: provider };
+ const submitValues = { ...cloneDeep(providerState), ...value, kind: provider };
await mutateAsync(submitValues);
},
[mutateAsync],
diff --git a/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdValidationStep/AddExternalOpenIdValidationStep.tsx b/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdValidationStep/AddExternalOpenIdValidationStep.tsx
index 63cca592a..498ff8a6d 100644
--- a/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdValidationStep/AddExternalOpenIdValidationStep.tsx
+++ b/web/src/pages/AddExternalOpenIdWizardPage/steps/AddExternalOpenIdValidationStep/AddExternalOpenIdValidationStep.tsx
@@ -37,30 +37,26 @@ export const AddExternalOpenIdValidationStep = () => {
{result && (
<>
- {'External ID provider successfully added.'}
+ {m.settings_openid_provider_validation_success_title()}
- {
- 'The connection to the external identity provider has been successfully verified.'
- }
+ {m.settings_openid_provider_validation_success_body()}
- {`The connection to your external identity provider is now verified. Your users can now log in using this provider for a faster and more convenient authentication experience.`}
+ {m.settings_openid_provider_validation_success_detail()}
>
)}
{!result && (
<>
- {'External ID provider successfully added.'}
+ {m.settings_openid_provider_validation_failure_title()}
- {
- 'The connection to the external identity provider has been successfully verified.'
- }
+ {m.settings_openid_provider_validation_failure_body()}
{isPresent(message) && (
<>
@@ -68,7 +64,7 @@ export const AddExternalOpenIdValidationStep = () => {
>
)}
From d12546425329b6229fa484158b80d792d4cf5fb7 Mon Sep 17 00:00:00 2001
From: Kuba <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 10 Apr 2026 13:34:20 +0200
Subject: [PATCH 3/7] change order on edit page, fix validation with directory
sync
---
.../form/EditJumpCloudProviderForm.tsx | 39 ++++++++++++-------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditJumpCloudProviderForm.tsx b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditJumpCloudProviderForm.tsx
index 9889d9164..c7bb77875 100644
--- a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditJumpCloudProviderForm.tsx
+++ b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditJumpCloudProviderForm.tsx
@@ -33,6 +33,19 @@ const discriminatedSchema = z.discriminatedUnion('directory_sync_enabled', [
syncSchema,
]);
+const validationSchema = syncSchema
+ .omit({ jumpcloud_api_key: true })
+ .extend({ jumpcloud_api_key: z.string() })
+ .superRefine((val, ctx) => {
+ if (val.directory_sync_enabled && val.jumpcloud_api_key.trim().length === 0) {
+ ctx.addIssue({
+ path: ['jumpcloud_api_key'],
+ code: 'custom',
+ message: m.form_error_required(),
+ });
+ }
+ });
+
type FormFields = z.infer;
export const EditJumpCloudProviderForm = ({
@@ -60,8 +73,8 @@ export const EditJumpCloudProviderForm = ({
defaultValues,
validationLogic: formChangeLogic,
validators: {
- onSubmit: syncSchema,
- onChange: syncSchema,
+ onSubmit: validationSchema,
+ onChange: validationSchema,
},
onSubmit: async ({ value }) => {
await onSubmit(value);
@@ -109,17 +122,6 @@ export const EditJumpCloudProviderForm = ({
)}
-
- {(field) => (
-
- )}
-
-
{(field) => (
)}
+
+
+ {(field) => (
+
+ )}
+
)}
From 26b873bf5493b3e140a84f1f3f994d932645cf37 Mon Sep 17 00:00:00 2001
From: Kuba <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 10 Apr 2026 15:53:17 +0200
Subject: [PATCH 4/7] test directory sync during provider edit
---
.../SettingsEditOpenIdProviderPage.tsx | 25 +++++++++++++++----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx b/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx
index 8c5ebe48a..ab69966e4 100644
--- a/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx
+++ b/web/src/pages/settings/SettingsEditOpenIdProviderPage/SettingsEditOpenIdProviderPage.tsx
@@ -38,9 +38,6 @@ export const SettingsEditOpenIdProviderPage = () => {
const { mutateAsync } = useMutation({
mutationFn: api.openIdProvider.editOpenIdProvider,
- onSuccess: () => {
- router.history.back();
- },
meta: {
invalidate: [['settings'], ['info'], ['openid']],
},
@@ -68,10 +65,28 @@ export const SettingsEditOpenIdProviderPage = () => {
...formData,
directory_sync_group_match: joinCsv(formData.directory_sync_group_match),
};
- await mutateAsync({ ...normalizedFormData, ...values });
+ const submitValues = { ...normalizedFormData, ...values };
+ await mutateAsync(submitValues);
+ if (values.directory_sync_enabled) {
+ try {
+ const { data: result } = await api.openIdProvider.testDirectorySync();
+ if (!result.success) {
+ await mutateAsync({ ...submitValues, directory_sync_enabled: false });
+ Snackbar.error(
+ result.message ?? m.settings_openid_provider_validation_failure_title(),
+ );
+ return;
+ }
+ } catch (_) {
+ await mutateAsync({ ...submitValues, directory_sync_enabled: false });
+ Snackbar.error(m.settings_openid_provider_validation_failure_title());
+ return;
+ }
+ }
+ router.history.back();
}
},
- [formData, mutateAsync],
+ [formData, mutateAsync, router],
);
if (!formData) return null;
From 21199dd509ecd2f42baba7d4c94dab0d9c4ca530 Mon Sep 17 00:00:00 2001
From: Kuba <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 10 Apr 2026 15:57:37 +0200
Subject: [PATCH 5/7] add missing spacing
---
.../form/EditMicrosoftProviderForm.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditMicrosoftProviderForm.tsx b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditMicrosoftProviderForm.tsx
index 3ca2c5239..2ac8f449b 100644
--- a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditMicrosoftProviderForm.tsx
+++ b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditMicrosoftProviderForm.tsx
@@ -109,6 +109,7 @@ export const EditMicrosoftProviderForm = ({
/>
)}
+
{(field) => (
Date: Fri, 10 Apr 2026 16:14:43 +0200
Subject: [PATCH 6/7] fix google form
---
.../form/EditGoogleProviderForm.tsx | 32 +++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx
index 7c169c4b6..55b7cda98 100644
--- a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx
+++ b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx
@@ -38,6 +38,34 @@ const discriminatedSchema = z.discriminatedUnion('directory_sync_enabled', [
syncSchema,
]);
+const validationSchema = syncSchema
+ .omit({ admin_email: true, google_service_account_file: true })
+ .extend({
+ admin_email: z.string().trim(),
+ google_service_account_file: z
+ .file(m.form_error_required())
+ .mime('application/json', m.form_error_file_format())
+ .nullable(),
+ })
+ .superRefine((val, ctx) => {
+ if (val.directory_sync_enabled) {
+ if (val.admin_email.trim().length === 0) {
+ ctx.addIssue({
+ path: ['admin_email'],
+ code: 'custom',
+ message: m.form_error_required(),
+ });
+ }
+ if (val.google_service_account_file === null) {
+ ctx.addIssue({
+ path: ['google_service_account_file'],
+ code: 'custom',
+ message: m.form_error_required(),
+ });
+ }
+ }
+ });
+
type FormFields = z.infer;
export const EditGoogleProviderForm = ({
@@ -72,8 +100,8 @@ export const EditGoogleProviderForm = ({
defaultValues,
validationLogic: formChangeLogic,
validators: {
- onSubmit: syncSchema,
- onChange: syncSchema,
+ onSubmit: validationSchema,
+ onChange: validationSchema,
},
onSubmit: async ({ value }) => {
if (value.directory_sync_enabled) {
From 6b1770e481b3bcae356e1e7f89a106ddac1788a7 Mon Sep 17 00:00:00 2001
From: Kuba <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 10 Apr 2026 16:24:53 +0200
Subject: [PATCH 7/7] fix file upload on google edit form
---
.../form/EditGoogleProviderForm.tsx | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx
index 55b7cda98..09ad22fe1 100644
--- a/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx
+++ b/web/src/pages/settings/SettingsEditOpenIdProviderPage/form/EditGoogleProviderForm.tsx
@@ -7,6 +7,7 @@ import { EditPageControls } from '../../../../shared/components/EditPageControls
import { EditPageFormSection } from '../../../../shared/components/EditPageFormSection/EditPageFormSection';
import { Fold } from '../../../../shared/defguard-ui/components/Fold/Fold';
import { SizedBox } from '../../../../shared/defguard-ui/components/SizedBox/SizedBox';
+import { Snackbar } from '../../../../shared/defguard-ui/providers/snackbar/snackbar';
import { ThemeSpacing } from '../../../../shared/defguard-ui/types';
import { useAppForm } from '../../../../shared/form';
import { formChangeLogic } from '../../../../shared/formLogic';
@@ -42,10 +43,7 @@ const validationSchema = syncSchema
.omit({ admin_email: true, google_service_account_file: true })
.extend({
admin_email: z.string().trim(),
- google_service_account_file: z
- .file(m.form_error_required())
- .mime('application/json', m.form_error_file_format())
- .nullable(),
+ google_service_account_file: z.file(m.form_error_required()).nullable(),
})
.superRefine((val, ctx) => {
if (val.directory_sync_enabled) {
@@ -107,10 +105,14 @@ export const EditGoogleProviderForm = ({
if (value.directory_sync_enabled) {
const inner = value as z.infer;
const file = await parseGoogleKeyFile(inner.google_service_account_file as File);
+ if (!file) {
+ Snackbar.error(m.form_error_file_contents());
+ return;
+ }
await onSubmit({
...omit(inner, ['google_service_account_file']),
- google_service_account_email: file?.client_email,
- google_service_account_key: file?.private_key,
+ google_service_account_email: file.client_email,
+ google_service_account_key: file.private_key,
});
} else {
await onSubmit(omit(value, ['google_service_account_file']));