;
+
+/**
+ * TODO: Should align this with the guard `samlServiceProviderMetadataGuard` defined in {@link logto/core/src/sso/types/saml.ts}.
+ * This only applies to SAML SSO connectors.
+ */
+const providerPropertiesGuard = z.object({
+ assertionConsumerServiceUrl: z.string().min(1),
+ entityId: z.string().min(1),
+});
+
+function BasicInfo({ ssoConnectorId, providerName, providerProperties }: Props) {
+ const { tenantEndpoint } = useContext(AppDataContext);
+ const { applyDomain: applyCustomDomain } = useCustomDomain();
+
+ if (providerName === SsoProviderName.OIDC) {
+ return (
+
+
+ {/* Generated and passed in by Admin console. */}
+
+
+
+ );
+ }
+
+ const result = providerPropertiesGuard.safeParse(providerProperties);
+
+ /**
+ * Used fallback to show the default value anyways but the cases should not happen.
+ * TODO: @darcyYe refactor to remove the manual guard.
+ */
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default BasicInfo;
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/OidcMetadataForm/index.tsx b/packages/console/src/pages/EnterpriseSso/Guide/OidcMetadataForm/index.tsx
new file mode 100644
index 000000000..f3898baf4
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/OidcMetadataForm/index.tsx
@@ -0,0 +1,29 @@
+import { useFormContext } from 'react-hook-form';
+
+import FormField from '@/ds-components/FormField';
+import TextInput from '@/ds-components/TextInput';
+
+import { type OidcGuideFormType } from '../../types.js';
+
+function OidcMetadataForm() {
+ const { register } = useFormContext();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default OidcMetadataForm;
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/SamlAttributeMapping/index.module.scss b/packages/console/src/pages/EnterpriseSso/Guide/SamlAttributeMapping/index.module.scss
new file mode 100644
index 000000000..957cdf7d7
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/SamlAttributeMapping/index.module.scss
@@ -0,0 +1,39 @@
+@use '@/scss/underscore' as _;
+
+.copyToClipboard {
+ display: block;
+}
+
+.table {
+ width: 100%;
+}
+
+.row {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ gap: _.unit(4);
+ padding-bottom: _.unit(3);
+
+ > td,
+ th {
+ width: calc((100% - _.unit(4)) / 2);
+ }
+}
+
+.header {
+ width: 100%;
+ font: var(--font-title-3);
+
+ > tr {
+ padding-bottom: _.unit(3);
+ }
+
+ * > th {
+ text-align: left;
+ }
+}
+
+.body {
+ width: 100%;
+}
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/SamlAttributeMapping/index.tsx b/packages/console/src/pages/EnterpriseSso/Guide/SamlAttributeMapping/index.tsx
new file mode 100644
index 000000000..a1996f92e
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/SamlAttributeMapping/index.tsx
@@ -0,0 +1,74 @@
+import { useMemo } from 'react';
+import { useFormContext } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+
+import CopyToClipboard from '@/ds-components/CopyToClipboard';
+import DynamicT from '@/ds-components/DynamicT';
+import TextInput from '@/ds-components/TextInput';
+
+import { attributeKeys, type SamlGuideFormType, type AttributeMapping } from '../../types.js';
+
+import * as styles from './index.module.scss';
+
+type Props = {
+ isReadOnly?: boolean;
+};
+
+const primaryKey = 'attributeMapping';
+
+function SamlAttributeMapping({ isReadOnly }: Props) {
+ const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
+ const { watch, register } = useFormContext();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const attributeMapping = watch(primaryKey) ?? {};
+ const attributeMappingEntries = useMemo<
+ Array<[keyof AttributeMapping, string | undefined]>
+ >(() => {
+ return attributeKeys.map((key) => [key, attributeMapping[key] ?? '']);
+ }, [attributeMapping]);
+
+ return (
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+
+ {attributeMappingEntries.map(([key, value]) => {
+ return (
+
+
+
+ |
+
+ {isReadOnly ? (
+
+ ) : (
+
+ )}
+ |
+
+ );
+ })}
+
+
+
+ );
+}
+
+export default SamlAttributeMapping;
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/SwitchFormatButton/index.module.scss b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/SwitchFormatButton/index.module.scss
new file mode 100644
index 000000000..c5543abc0
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/SwitchFormatButton/index.module.scss
@@ -0,0 +1,35 @@
+@use '@/scss/underscore' as _;
+
+.dropdownIcon {
+ color: var(--color-text-link);
+}
+
+.dropdown {
+ min-width: unset;
+}
+
+.icon {
+ width: 20px;
+ height: 20px;
+ flex-shrink: 0;
+ color: transparent;
+
+ &.selected {
+ color: var(--color-primary-40);
+ }
+}
+
+.title {
+ display: flex;
+ align-items: center;
+ margin-left: _.unit(1);
+
+ .optionText {
+ font: var(--font-body-2);
+ margin-left: _.unit(3);
+ }
+
+ &.selected {
+ color: var(--color-primary-40);
+ }
+}
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/SwitchFormatButton/index.tsx b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/SwitchFormatButton/index.tsx
new file mode 100644
index 000000000..68b21d842
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/SwitchFormatButton/index.tsx
@@ -0,0 +1,72 @@
+import { type AdminConsoleKey } from '@logto/phrases';
+import classNames from 'classnames';
+import { useTranslation } from 'react-i18next';
+
+import SwitchArrowIcon from '@/assets/icons/switch-arrow.svg';
+import Tick from '@/assets/icons/tick.svg';
+import ActionMenu from '@/ds-components/ActionMenu';
+import { DropdownItem } from '@/ds-components/Dropdown';
+import DynamicT from '@/ds-components/DynamicT';
+
+import * as styles from './index.module.scss';
+
+type Props = {
+ value: FormFormat;
+ onChange: (formFormat: FormFormat) => void;
+};
+
+export enum FormFormat {
+ Url = 'url',
+ Xml = 'xml',
+ Manual = 'manual',
+}
+
+type Options = {
+ value: FormFormat;
+ title: AdminConsoleKey;
+};
+
+const options: Options[] = [
+ { value: FormFormat.Url, title: 'enterprise_sso.metadata.metadata_format_url' },
+ { value: FormFormat.Xml, title: 'enterprise_sso.metadata.metadata_format_xml' },
+ { value: FormFormat.Manual, title: 'enterprise_sso.metadata.metadata_format_manual' },
+];
+
+function SwitchFormatButton({ value, onChange }: Props) {
+ const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
+ return (
+ ,
+ }}
+ dropdownHorizontalAlign="start"
+ dropdownClassName={styles.dropdown}
+ title={t('enterprise_sso.metadata.dropdown_title')}
+ >
+ {options.map(({ value: optionValue, title }) => (
+ {
+ onChange(optionValue);
+ }}
+ >
+
+
+
+
+
+ ))}
+
+ );
+}
+
+export default SwitchFormatButton;
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/index.module.scss b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/index.module.scss
new file mode 100644
index 000000000..c1044d7e7
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/index.module.scss
@@ -0,0 +1,13 @@
+@use '@/scss/underscore' as _;
+
+.description {
+ color: var(--color-text-secondary);
+ font: var(--font-body-2);
+ margin-top: _.unit(0.5);
+}
+
+.samlMetadataForm {
+ > div:not(:first-child) {
+ margin-top: _.unit(6);
+ }
+}
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/index.tsx b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/index.tsx
new file mode 100644
index 000000000..b10071e61
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/SamlMetadataForm/index.tsx
@@ -0,0 +1,108 @@
+import { conditional, pick } from '@silverhand/essentials';
+import { useState } from 'react';
+import { useFormContext } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+
+import FormField from '@/ds-components/FormField';
+import TextInput from '@/ds-components/TextInput';
+import Textarea from '@/ds-components/Textarea';
+
+import { type SamlGuideFormType } from '../../types.js';
+
+import SwitchFormatButton, { FormFormat } from './SwitchFormatButton';
+import * as styles from './index.module.scss';
+
+/**
+ * Since we need to reset some of the form fields when we switch the form format
+ * for SAML configuration form, here we define this object for convenience.
+ */
+const completeResetObject: Omit = {
+ metadata: undefined,
+ metadataUrl: undefined,
+ signInEndpoint: undefined,
+ entityId: undefined,
+ x509Certificate: undefined,
+};
+
+type Props = {
+ formFormat: FormFormat;
+};
+
+function SamlMetadataFormFields({ formFormat }: Props) {
+ const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
+ const { register } = useFormContext();
+
+ switch (formFormat) {
+ case FormFormat.Manual: {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ );
+ }
+ case FormFormat.Xml: {
+ return (
+
+
+
+ );
+ }
+ case FormFormat.Url: {
+ return (
+
+
+
+ {t('enterprise_sso.metadata.saml.metadata_url_description')}
+
+
+ );
+ }
+ default: {
+ return null;
+ }
+ }
+}
+
+function SamlMetadataForm() {
+ const { reset } = useFormContext();
+ const [formFormat, setFormFormat] = useState(FormFormat.Url);
+
+ // If some form format is selected, then fields from other fields should be cleared.
+ const onSelect = (formFormat: FormFormat) => {
+ reset({
+ ...conditional(
+ formFormat === FormFormat.Url &&
+ pick(completeResetObject, 'metadata', 'entityId', 'signInEndpoint', 'x509Certificate')
+ ),
+ ...conditional(
+ formFormat === FormFormat.Xml &&
+ pick(completeResetObject, 'metadataUrl', 'entityId', 'signInEndpoint', 'x509Certificate')
+ ),
+ ...conditional(
+ formFormat === FormFormat.Manual && pick(completeResetObject, 'metadata', 'metadataUrl')
+ ),
+ });
+
+ setFormFormat(formFormat);
+ };
+
+ return (
+
+
+
+
+ );
+}
+
+export default SamlMetadataForm;
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/index.module.scss b/packages/console/src/pages/EnterpriseSso/Guide/index.module.scss
new file mode 100644
index 000000000..65cfa91c1
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/index.module.scss
@@ -0,0 +1,129 @@
+@use '@/scss/underscore' as _;
+
+.container {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--color-base);
+ height: 100vh;
+ overflow-x: auto;
+
+ .header {
+ display: flex;
+ align-items: center;
+ background: none;
+ height: 64px;
+ padding: 0 _.unit(21) 0 _.unit(2);
+
+ button {
+ margin-left: _.unit(4);
+ }
+
+ .separator {
+ @include _.vertical-bar;
+ height: 20px;
+ margin: 0 _.unit(5) 0 _.unit(4);
+ }
+
+ .closeIcon {
+ color: var(--color-text-secondary);
+ }
+ }
+
+ .content {
+ flex: 1;
+ display: flex;
+ overflow: auto;
+ justify-content: center;
+ min-width: min-content;
+ padding: _.unit(2) _.unit(6) _.unit(6);
+
+ > * {
+ flex: 1;
+ max-width: 800px;
+ min-width: 400px;
+ }
+
+ .readme {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--color-layer-1);
+ border: 1.5px solid var(--color-focused-variant);
+ border-radius: 16px;
+ margin: 0 _.unit(6) 0 0;
+ overflow-y: auto;
+ position: sticky;
+ top: 0;
+
+ .readmeTitle {
+ font: var(--font-title-2);
+ padding: _.unit(5) _.unit(6) _.unit(4);
+ border-bottom: 1px solid var(--color-focused-variant);
+ }
+
+ .readmeContent {
+ flex: 1;
+ padding: 0 _.unit(6) _.unit(4);
+
+ h2 {
+ color: var(--color-text);
+ }
+
+ h3 {
+ color: var(--color-text-secondary);
+ }
+ }
+ }
+
+ .setup {
+ padding-bottom: _.unit(6);
+
+ .block {
+ background-color: var(--color-layer-1);
+ border-radius: 16px;
+ padding: 0 _.unit(6) _.unit(6);
+ margin-bottom: _.unit(4);
+
+ .blockTitle {
+ font: var(--font-title-2);
+ padding: _.unit(5) 0 _.unit(6);
+ display: flex;
+ flex-direction: column;
+ gap: _.unit(2);
+
+ .numberedTitle {
+ display: flex;
+ align-items: center;
+ flex-direction: row;
+ gap: _.unit(4);
+ }
+
+ .number {
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background-color: var(--color-focused-variant);
+ color: var(--color-primary);
+ font: var(--font-title-2);
+ text-align: center;
+ line-height: 28px;
+ }
+
+ .blockSubtitle {
+ font: var(--font-body-2);
+ color: var(--color-text-secondary);
+ }
+ }
+ }
+
+ .footer {
+ padding-bottom: _.unit(10);
+ display: flex;
+ justify-content: right;
+ }
+ }
+
+ form + div {
+ margin-top: _.unit(6);
+ }
+ }
+}
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/index.tsx b/packages/console/src/pages/EnterpriseSso/Guide/index.tsx
new file mode 100644
index 000000000..ce41b69bc
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/index.tsx
@@ -0,0 +1,187 @@
+import { type AdminConsoleKey } from '@logto/phrases';
+import { SsoProviderName, type SsoConnectorWithProviderConfig } from '@logto/schemas';
+import cleanDeep from 'clean-deep';
+import type { ReactNode } from 'react';
+import { FormProvider, useForm } from 'react-hook-form';
+import Modal from 'react-modal';
+
+import Close from '@/assets/icons/close.svg';
+import Markdown from '@/components/Markdown';
+import Button from '@/ds-components/Button';
+import CardTitle from '@/ds-components/CardTitle';
+import DangerousRaw from '@/ds-components/DangerousRaw';
+import DynamicT from '@/ds-components/DynamicT';
+import IconButton from '@/ds-components/IconButton';
+import OverlayScrollbar from '@/ds-components/OverlayScrollbar';
+import useApi from '@/hooks/use-api';
+import * as modalStyles from '@/scss/modal.module.scss';
+import { trySubmitSafe } from '@/utils/form';
+
+import { splitMarkdownByTitle } from '../../Connectors/utils.js';
+import { type GuideFormType } from '../types.js';
+
+import BasicInfo from './BasicInfo';
+import OidcMetadataForm from './OidcMetadataForm';
+import SamlAttributeMapping from './SamlAttributeMapping';
+import SamlMetadataForm from './SamlMetadataForm';
+import * as styles from './index.module.scss';
+import { type SsoConnectorWithProviderConfigWithGeneric } from './types.js';
+
+type Props = {
+ isOpen: boolean;
+ connector: SsoConnectorWithProviderConfigWithGeneric;
+ onClose: (ssoConnectorId?: string) => void;
+ isReadOnly?: boolean;
+};
+
+type GuideCardProps = {
+ cardOrder: number;
+ children: ReactNode;
+ title: AdminConsoleKey;
+ description: AdminConsoleKey;
+};
+
+function GuideCard({ cardOrder, title, description, children }: GuideCardProps) {
+ return (
+
+ );
+}
+
+function Guide({ isOpen, connector, onClose, isReadOnly }: Props) {
+ const {
+ id: ssoConnectorId,
+ connectorName: ssoConnectorName,
+ providerName,
+ providerProperties,
+ } = connector;
+
+ const api = useApi();
+
+ const methods = useForm>();
+
+ const {
+ formState: { isSubmitting },
+ handleSubmit,
+ } = methods;
+
+ // TODO: @darcyYe Add SSO connector README.
+ const { title, content } = splitMarkdownByTitle(
+ '# SSO connector guide\n\nThis is a guide for Logto Enterprise SSO connector.'
+ );
+
+ const onSubmit = handleSubmit(
+ trySubmitSafe(async (formData) => {
+ if (isSubmitting) {
+ return;
+ }
+
+ await api
+ .patch(`api/sso-connectors/${ssoConnectorId}/config`, {
+ json: cleanDeep(formData),
+ })
+ .json();
+
+ onClose(ssoConnectorId);
+ })
+ );
+
+ return (
+ {
+ onClose();
+ }}
+ >
+
+
+
{
+ onClose(ssoConnectorId);
+ }}
+ >
+
+
+
+
{ssoConnectorName}}
+ subtitle="enterprise_sso.guide.subtitle"
+ />
+
+
+
+ README: {title}
+ {content}
+
+
+
+
+
+ );
+}
+
+export default Guide;
diff --git a/packages/console/src/pages/EnterpriseSso/Guide/types.ts b/packages/console/src/pages/EnterpriseSso/Guide/types.ts
new file mode 100644
index 000000000..d245735c3
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/Guide/types.ts
@@ -0,0 +1,9 @@
+import { type SsoProviderName, type SsoConnectorWithProviderConfig } from '@logto/schemas';
+
+// Help the Guide component type to be inferred from the connector's type.
+export type SsoConnectorWithProviderConfigWithGeneric = Omit<
+ SsoConnectorWithProviderConfig,
+ 'providerName'
+> & {
+ providerName: T;
+};
diff --git a/packages/console/src/pages/EnterpriseSso/SsoCreationModal/index.tsx b/packages/console/src/pages/EnterpriseSso/SsoCreationModal/index.tsx
index 33f87cdec..4557e84e5 100644
--- a/packages/console/src/pages/EnterpriseSso/SsoCreationModal/index.tsx
+++ b/packages/console/src/pages/EnterpriseSso/SsoCreationModal/index.tsx
@@ -1,4 +1,7 @@
-import { type SsoConnectorFactoriesResponse, type SsoConnector } from '@logto/schemas';
+import {
+ type SsoConnectorFactoriesResponse,
+ type SsoConnectorWithProviderConfig,
+} from '@logto/schemas';
import { useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -22,7 +25,7 @@ import * as styles from './index.module.scss';
type Props = {
isOpen: boolean;
- onClose: (ssoConnectorId?: string) => void;
+ onClose: (ssoConnector?: SsoConnectorWithProviderConfig) => void;
};
type FormType = {
@@ -61,10 +64,10 @@ function SsoCreationModal({ isOpen, onClose: rawOnClose }: Props) {
);
// `rawOnClose` does not clean the state of the modal.
- const onClose = (ssoConnectorId?: string) => {
+ const onClose = (ssoConnector?: SsoConnectorWithProviderConfig) => {
setSelectedProviderName(undefined);
reset();
- rawOnClose(ssoConnectorId);
+ rawOnClose(ssoConnector);
};
const handleSsoSelection = (providerName: string) => {
@@ -79,9 +82,9 @@ function SsoCreationModal({ isOpen, onClose: rawOnClose }: Props) {
const createdSsoConnector = await api
.post(`api/sso-connectors`, { json: { ...formData, providerName: selectedProviderName } })
- .json();
+ .json();
- onClose(createdSsoConnector.id);
+ onClose(createdSsoConnector);
})
);
diff --git a/packages/console/src/pages/EnterpriseSso/index.tsx b/packages/console/src/pages/EnterpriseSso/index.tsx
index beabbe040..eddf9e802 100644
--- a/packages/console/src/pages/EnterpriseSso/index.tsx
+++ b/packages/console/src/pages/EnterpriseSso/index.tsx
@@ -1,8 +1,9 @@
import { withAppInsights } from '@logto/app-insights/react';
import { type SsoConnectorWithProviderConfig, Theme } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
+import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useLocation } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom';
import useSWR from 'swr';
import Plus from '@/assets/icons/plus.svg';
@@ -21,21 +22,24 @@ import useTenantPathname from '@/hooks/use-tenant-pathname';
import useTheme from '@/hooks/use-theme';
import { buildUrl } from '@/utils/url';
+import Guide from './Guide';
import SsoCreationModal from './SsoCreationModal';
import * as styles from './index.module.scss';
const pageSize = defaultPageSize;
const enterpriseSsoPathname = '/enterprise-sso';
const createEnterpriseSsoPathname = `${enterpriseSsoPathname}/create`;
-const buildGuidePathname = (id: string) => `${enterpriseSsoPathname}/${id}/guide`;
const buildDetailsPathname = (id: string) => `${enterpriseSsoPathname}/${id}`;
+const buildGuidePathname = (id: string) => `${buildDetailsPathname(id)}/guide`;
function EnterpriseSsoConnectors() {
const theme = useTheme();
const { pathname } = useLocation();
const { navigate } = useTenantPathname();
+ const { id } = useParams();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
+ const [connectorForGuide, setConnectorForGuide] = useState();
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({
page: 1,
});
@@ -52,6 +56,15 @@ function EnterpriseSsoConnectors() {
const isLoading = !data && !error;
const [ssoConnectors, totalCount] = data ?? [];
+ useEffect(() => {
+ const selectedSsoConnector = ssoConnectors?.find(
+ ({ id: ssoConnectorId }) => ssoConnectorId === id
+ );
+ if (selectedSsoConnector) {
+ setConnectorForGuide(selectedSsoConnector);
+ }
+ }, [id, ssoConnectors]);
+
return (
{
- navigate({ pathname: createEnterpriseSsoPathname });
+ navigate(createEnterpriseSsoPathname);
},
}
)}
@@ -159,7 +172,7 @@ function EnterpriseSsoConnectors() {
size="large"
icon={}
onClick={() => {
- navigate({ pathname: createEnterpriseSsoPathname });
+ navigate(createEnterpriseSsoPathname);
}}
/>
}
@@ -168,17 +181,38 @@ function EnterpriseSsoConnectors() {
onRetry: async () => mutate(undefined, true),
}}
widgets={
- {
- if (id) {
- navigate(buildGuidePathname(id), { replace: true });
- return;
- }
+ <>
+ {
+ if (ssoConnector) {
+ await mutate([[...(ssoConnectors ?? []), ssoConnector], totalCount ?? 0 + 1]);
+ navigate(buildGuidePathname(ssoConnector.id));
+ return;
+ }
- navigate(enterpriseSsoPathname);
- }}
- />
+ navigate(enterpriseSsoPathname);
+ }}
+ />
+ {
+ /** Add this filter to make TypeScript happy, if `connectorForGuide` does not exist, the route will not come to this path. */
+ connectorForGuide && (
+ {
+ if (connectorId) {
+ navigate(buildDetailsPathname(connectorId), { replace: true });
+ return;
+ }
+
+ navigate(enterpriseSsoPathname);
+ }}
+ />
+ )
+ }
+ >
}
/>
);
diff --git a/packages/console/src/pages/EnterpriseSso/types.ts b/packages/console/src/pages/EnterpriseSso/types.ts
new file mode 100644
index 000000000..1ff665632
--- /dev/null
+++ b/packages/console/src/pages/EnterpriseSso/types.ts
@@ -0,0 +1,44 @@
+/**
+ * Type definitions for Enterprise SSO guide form, since the type of SAML config is defined in
+ * @logto/core and can not be imported here, should align with SAML config types.
+ * See {@link @logto/core/packages/core/src/sso/SamlConnector/index.ts}.
+ */
+import { type SsoProviderName } from '@logto/schemas';
+
+export type AttributeMapping = {
+ id?: string;
+ email?: string;
+ phone?: string;
+ name?: string;
+ avatar?: string;
+};
+
+export const attributeKeys = Object.freeze([
+ 'id',
+ 'email',
+ 'phone',
+ 'name',
+ 'avatar',
+]) satisfies ReadonlyArray;
+
+export type SamlGuideFormType = {
+ metadataUrl?: string;
+ metadata?: string;
+ signInEndpoint?: string;
+ entityId?: string;
+ x509Certificate?: string;
+ attributeMapping?: AttributeMapping;
+};
+
+export type OidcGuideFormType = {
+ clientId?: string;
+ clientSecret?: string;
+ issuer?: string;
+ scope?: string;
+};
+
+export type GuideFormType = T extends SsoProviderName.OIDC
+ ? OidcGuideFormType
+ : T extends SsoProviderName.SAML
+ ? SamlGuideFormType
+ : never;
diff --git a/packages/core/src/__mocks__/sso.ts b/packages/core/src/__mocks__/sso.ts
index 001427586..c4fee57ee 100644
--- a/packages/core/src/__mocks__/sso.ts
+++ b/packages/core/src/__mocks__/sso.ts
@@ -1,6 +1,4 @@
-import { type SsoConnector } from '@logto/schemas';
-
-import { SsoProviderName } from '#src/sso/types/index.js';
+import { type SsoConnector, SsoProviderName } from '@logto/schemas';
export const mockSsoConnector = {
id: 'mock-sso-connector',
diff --git a/packages/core/src/libraries/sso-connector.ts b/packages/core/src/libraries/sso-connector.ts
index 3ff350b22..4c4c41ead 100644
--- a/packages/core/src/libraries/sso-connector.ts
+++ b/packages/core/src/libraries/sso-connector.ts
@@ -1,8 +1,8 @@
+import { type SupportedSsoConnector } from '@logto/schemas';
import { assert } from '@silverhand/essentials';
import RequestError from '#src/errors/RequestError/index.js';
import { ssoConnectorFactories } from '#src/sso/index.js';
-import { type SupportedSsoConnector } from '#src/sso/types/index.js';
import { isSupportedSsoConnector } from '#src/sso/utils.js';
import type Queries from '#src/tenants/Queries.js';
diff --git a/packages/core/src/routes/interaction/utils/single-sign-on.ts b/packages/core/src/routes/interaction/utils/single-sign-on.ts
index 9ec65e9f3..482da5dd8 100644
--- a/packages/core/src/routes/interaction/utils/single-sign-on.ts
+++ b/packages/core/src/routes/interaction/utils/single-sign-on.ts
@@ -1,6 +1,11 @@
import { ConnectorError, type SocialUserInfo } from '@logto/connector-kit';
import { validateRedirectUrl } from '@logto/core-kit';
-import { InteractionEvent, type User, type UserSsoIdentity } from '@logto/schemas';
+import {
+ InteractionEvent,
+ type User,
+ type UserSsoIdentity,
+ type SupportedSsoConnector,
+} from '@logto/schemas';
import { generateStandardId } from '@logto/shared';
import { conditional } from '@silverhand/essentials';
import { z } from 'zod';
@@ -9,10 +14,7 @@ import RequestError from '#src/errors/RequestError/index.js';
import { type WithLogContext } from '#src/middleware/koa-audit-log.js';
import { type WithInteractionDetailsContext } from '#src/routes/interaction/middleware/koa-interaction-details.js';
import { ssoConnectorFactories } from '#src/sso/index.js';
-import {
- type SupportedSsoConnector,
- type SingleSignOnConnectorSession,
-} from '#src/sso/types/index.js';
+import { type SingleSignOnConnectorSession } from '#src/sso/types/index.js';
import type Queries from '#src/tenants/Queries.js';
import type TenantContext from '#src/tenants/TenantContext.js';
import assertThat from '#src/utils/assert-that.js';
diff --git a/packages/core/src/routes/sso-connector/index.ts b/packages/core/src/routes/sso-connector/index.ts
index 57b6e996c..1c69c1e7d 100644
--- a/packages/core/src/routes/sso-connector/index.ts
+++ b/packages/core/src/routes/sso-connector/index.ts
@@ -5,7 +5,7 @@ import {
ssoConnectorWithProviderConfigGuard,
} from '@logto/schemas';
import { generateStandardShortId } from '@logto/shared';
-import { conditional, assert } from '@silverhand/essentials';
+import { conditional, assert, yes } from '@silverhand/essentials';
import { z } from 'zod';
import RequestError from '#src/errors/RequestError/index.js';
@@ -235,21 +235,33 @@ export default function singleSignOnRoutes(...args: Rout
`${pathname}/:id/config`,
koaGuard({
params: z.object({ id: z.string().min(1) }),
+ /**
+ * Allow partially validate the connector config, on the guide page after
+ * the SSO connector is created, we allow users to save incomplete config without validating it.
+ */
+ query: z.object({ partialValidateConfig: z.string().optional() }),
body: jsonObjectGuard,
response: ssoConnectorWithProviderConfigGuard,
status: [200, 404, 422],
}),
async (ctx, next) => {
- const { id } = ctx.guard.params;
- const { body } = ctx.guard;
+ const {
+ params: { id },
+ body,
+ query: { partialValidateConfig },
+ } = ctx.guard;
const { providerName, config } = await getSsoConnectorById(id);
// Merge with existing config and revalidate
- const parsedConfig = parseConnectorConfig(providerName, {
- ...config,
- ...body,
- });
+ const parsedConfig = parseConnectorConfig(
+ providerName,
+ {
+ ...config,
+ ...body,
+ },
+ yes(partialValidateConfig)
+ );
const connector = await ssoConnectors.updateById(id, {
config: parsedConfig,
diff --git a/packages/core/src/routes/sso-connector/utils.test.ts b/packages/core/src/routes/sso-connector/utils.test.ts
index eb4734164..86782c1f9 100644
--- a/packages/core/src/routes/sso-connector/utils.test.ts
+++ b/packages/core/src/routes/sso-connector/utils.test.ts
@@ -1,8 +1,8 @@
+import { SsoProviderName } from '@logto/schemas';
import { createMockUtils } from '@logto/shared/esm';
import { mockSsoConnector } from '#src/__mocks__/sso.js';
import RequestError from '#src/errors/RequestError/index.js';
-import { SsoProviderName } from '#src/sso/types/index.js';
const { jest } = import.meta;
const { mockEsmWithActual } = createMockUtils(jest);
diff --git a/packages/core/src/routes/sso-connector/utils.ts b/packages/core/src/routes/sso-connector/utils.ts
index 44f9fe3c5..7ebcc6896 100644
--- a/packages/core/src/routes/sso-connector/utils.ts
+++ b/packages/core/src/routes/sso-connector/utils.ts
@@ -1,5 +1,10 @@
import { type I18nPhrases } from '@logto/connector-kit';
-import { type JsonObject, type SsoConnectorWithProviderConfig } from '@logto/schemas';
+import type {
+ JsonObject,
+ SsoConnectorWithProviderConfig,
+ SupportedSsoConnector,
+ SsoProviderName,
+} from '@logto/schemas';
import { conditional, trySafe } from '@silverhand/essentials';
import RequestError from '#src/errors/RequestError/index.js';
@@ -8,7 +13,6 @@ import {
ssoConnectorFactories,
singleSignOnDomainBlackList,
} from '#src/sso/index.js';
-import { type SupportedSsoConnector, type SsoProviderName } from '#src/sso/types/index.js';
const isKeyOfI18nPhrases = (key: string, phrases: I18nPhrases): key is keyof I18nPhrases =>
key in phrases;
@@ -71,10 +75,16 @@ export const fetchConnectorProviderDetails = async (
return instance.getConfig();
});
+ const providerProperties = trySafe(() => {
+ const instance = new constructor(connector, tenantId);
+ return instance.getProperties();
+ });
+
return {
...connector,
providerLogo: logo,
...conditional(providerConfig && { providerConfig }),
+ ...conditional(providerProperties && { providerProperties }),
};
};
diff --git a/packages/core/src/sso/OidcSsoConnector/index.test.ts b/packages/core/src/sso/OidcSsoConnector/index.test.ts
index 13dd15cb1..c0c06c074 100644
--- a/packages/core/src/sso/OidcSsoConnector/index.test.ts
+++ b/packages/core/src/sso/OidcSsoConnector/index.test.ts
@@ -1,7 +1,7 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
+import { SsoProviderName } from '@logto/schemas';
import { mockSsoConnector } from '#src/__mocks__/sso.js';
-import { SsoProviderName } from '#src/sso/types/index.js';
import { oidcSsoConnectorFactory } from './index.js';
diff --git a/packages/core/src/sso/OidcSsoConnector/index.ts b/packages/core/src/sso/OidcSsoConnector/index.ts
index b597627fc..fbc4828e3 100644
--- a/packages/core/src/sso/OidcSsoConnector/index.ts
+++ b/packages/core/src/sso/OidcSsoConnector/index.ts
@@ -1,7 +1,5 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
-import { type SsoConnector } from '@logto/schemas';
-
-import { SsoProviderName } from '#src/sso/types/index.js';
+import { type SsoConnector, SsoProviderName } from '@logto/schemas';
import OidcConnector from '../OidcConnector/index.js';
import { type SingleSignOnFactory } from '../index.js';
@@ -23,6 +21,10 @@ export class OidcSsoConnector extends OidcConnector implements SingleSignOn {
return this._data;
}
+ // OIDC connector doesn't have additional properties.
+ // eslint-disable-next-line unicorn/no-useless-undefined
+ getProperties = () => undefined;
+
getConfig = async () => this.getOidcConfig();
getIssuer = async () => this.issuer;
}
diff --git a/packages/core/src/sso/SamlConnector/index.ts b/packages/core/src/sso/SamlConnector/index.ts
index 4cfe2f1d0..3e74e2d57 100644
--- a/packages/core/src/sso/SamlConnector/index.ts
+++ b/packages/core/src/sso/SamlConnector/index.ts
@@ -35,6 +35,7 @@ import {
* @property assertionConsumerServiceUrl The SAML connector's assertion consumer service URL {@link file://src/routes/authn.ts}
* @property _samlIdpMetadataXml The cached raw SAML metadata (in XML-format) from the raw SAML SSO connector config
*
+ * @method getSamlSpProperties Get the SAML service provider properties.
* @method getSamlIdpMetadata Parse and return SAML config from the SAML connector config. Throws error if config is invalid.
* @method parseSamlAssertion Parse and store the SAML assertion from IdP.
* @method getSingleSignOnUrl Get the SAML SSO URL.
@@ -69,6 +70,13 @@ class SamlConnector {
};
}
+ /**
+ * @returns Properties of the SAML service provider.
+ */
+ getSamlSpProperties() {
+ return this.serviceProviderMetadata;
+ }
+
/**
* Return parsed SAML metadata.
*
diff --git a/packages/core/src/sso/SamlSsoConnector/index.test.ts b/packages/core/src/sso/SamlSsoConnector/index.test.ts
index 8d0b8c35e..a021c7a55 100644
--- a/packages/core/src/sso/SamlSsoConnector/index.test.ts
+++ b/packages/core/src/sso/SamlSsoConnector/index.test.ts
@@ -1,7 +1,7 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
+import { SsoProviderName } from '@logto/schemas';
import { mockSsoConnector as _mockSsoConnector } from '#src/__mocks__/sso.js';
-import { SsoProviderName } from '#src/sso/types/index.js';
import { samlSsoConnectorFactory } from './index.js';
diff --git a/packages/core/src/sso/SamlSsoConnector/index.ts b/packages/core/src/sso/SamlSsoConnector/index.ts
index 71476b54e..0ce06aa32 100644
--- a/packages/core/src/sso/SamlSsoConnector/index.ts
+++ b/packages/core/src/sso/SamlSsoConnector/index.ts
@@ -1,13 +1,13 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
import { type SsoConnector } from '@logto/schemas';
+import { SsoProviderName } from '@logto/schemas';
-import { SsoProviderName } from '#src/sso/types/index.js';
import assertThat from '#src/utils/assert-that.js';
import SamlConnector from '../SamlConnector/index.js';
import { type SingleSignOnFactory } from '../index.js';
import { type SingleSignOn } from '../types/index.js';
-import { samlConnectorConfigGuard } from '../types/saml.js';
+import { type SamlServiceProviderMetadata, samlConnectorConfigGuard } from '../types/saml.js';
import {
type SingleSignOnConnectorSession,
type CreateSingleSignOnSession,
@@ -20,6 +20,7 @@ import {
*
* @property data The SAML connector data from the database
*
+ * @method getProperties Get the SAML service provider properties.
* @method getConfig Get parsed SAML config along with it's metadata. Throws error if config is invalid.
* @method getUserInfo Get social user info.
*/
@@ -44,6 +45,13 @@ export class SamlSsoConnector extends SamlConnector implements SingleSignOn {
return entityId;
}
+ /**
+ * @returns Properties of the SAML service provider.
+ */
+ getProperties(): SamlServiceProviderMetadata {
+ return this.getSamlSpProperties();
+ }
+
/**
* Get parsed SAML connector's config along with it's metadata. Throws error if config is invalid.
*
diff --git a/packages/core/src/sso/index.ts b/packages/core/src/sso/index.ts
index b17a534cf..4af641c6c 100644
--- a/packages/core/src/sso/index.ts
+++ b/packages/core/src/sso/index.ts
@@ -1,6 +1,5 @@
import { type I18nPhrases } from '@logto/connector-kit';
-
-import { SsoProviderName } from '#src/sso/types/index.js';
+import { SsoProviderName } from '@logto/schemas';
import { oidcSsoConnectorFactory, type OidcSsoConnector } from './OidcSsoConnector/index.js';
import { type SamlSsoConnector, samlSsoConnectorFactory } from './SamlSsoConnector/index.js';
diff --git a/packages/core/src/sso/types/index.ts b/packages/core/src/sso/types/index.ts
index b2e0b4093..e45d0f3e7 100644
--- a/packages/core/src/sso/types/index.ts
+++ b/packages/core/src/sso/types/index.ts
@@ -1,4 +1,5 @@
import { type JsonObject, type SsoConnector } from '@logto/schemas';
+import { type Optional } from '@silverhand/essentials';
export * from './session.js';
@@ -13,13 +14,5 @@ export abstract class SingleSignOn {
abstract data: SsoConnector;
abstract getConfig: () => Promise;
abstract getIssuer: () => Promise;
+ abstract getProperties: () => Optional;
}
-
-export enum SsoProviderName {
- OIDC = 'OIDC',
- SAML = 'SAML',
-}
-
-export type SupportedSsoConnector = Omit & {
- providerName: SsoProviderName;
-};
diff --git a/packages/core/src/sso/utils.test.ts b/packages/core/src/sso/utils.test.ts
index 1836e4cde..61b92b058 100644
--- a/packages/core/src/sso/utils.test.ts
+++ b/packages/core/src/sso/utils.test.ts
@@ -1,4 +1,4 @@
-import { SsoProviderName } from '#src/sso/types/index.js';
+import { SsoProviderName } from '@logto/schemas';
import { isSupportedSsoProvider } from './utils.js';
diff --git a/packages/core/src/sso/utils.ts b/packages/core/src/sso/utils.ts
index 2509520da..3b2a1379d 100644
--- a/packages/core/src/sso/utils.ts
+++ b/packages/core/src/sso/utils.ts
@@ -1,6 +1,4 @@
-import type { SsoConnector } from '@logto/schemas';
-
-import type { SupportedSsoConnector, SsoProviderName } from '#src/sso/types/index.js';
+import type { SsoConnector, SupportedSsoConnector, SsoProviderName } from '@logto/schemas';
import { ssoConnectorFactories } from './index.js';
diff --git a/packages/integration-tests/src/api/sso-connector.ts b/packages/integration-tests/src/api/sso-connector.ts
index 2dcb3a627..231afdec0 100644
--- a/packages/integration-tests/src/api/sso-connector.ts
+++ b/packages/integration-tests/src/api/sso-connector.ts
@@ -1,4 +1,5 @@
import { type CreateSsoConnector, type SsoConnector } from '@logto/schemas';
+import { conditional } from '@silverhand/essentials';
import { authedAdminApi } from '#src/api/api.js';
@@ -44,9 +45,14 @@ export const patchSsoConnectorById = async (id: string, data: Partial();
-export const patchSsoConnectorConfigById = async (id: string, data: Record) =>
+export const patchSsoConnectorConfigById = async (
+ id: string,
+ data: Record,
+ partialValidate = false
+) =>
authedAdminApi
.patch(`sso-connectors/${id}/config`, {
json: data,
+ ...conditional(partialValidate && { searchParams: { partialValidateConfig: 'true' } }),
})
.json();
diff --git a/packages/integration-tests/src/constants.ts b/packages/integration-tests/src/constants.ts
index c2312e503..1137ca018 100644
--- a/packages/integration-tests/src/constants.ts
+++ b/packages/integration-tests/src/constants.ts
@@ -1,4 +1,9 @@
-import { type CreateSsoConnector, SignInIdentifier, demoAppApplicationId } from '@logto/schemas';
+import {
+ type CreateSsoConnector,
+ SignInIdentifier,
+ demoAppApplicationId,
+ SsoProviderName,
+} from '@logto/schemas';
import { appendPath, getEnv } from '@silverhand/essentials';
export const logtoUrl = getEnv('INTEGRATION_TESTS_LOGTO_URL', 'http://localhost:3001');
@@ -26,11 +31,6 @@ export const consoleUsername = 'svhd';
export const consolePassword = 'silverhandasd_1';
export const mockSocialAuthPageUrl = 'http://mock.social.com';
-export enum SsoProviderName {
- OIDC = 'OIDC',
- SAML = 'SAML',
-}
-
export const newOidcSsoConnectorPayload = {
providerName: SsoProviderName.OIDC,
connectorName: 'test-oidc',
diff --git a/packages/integration-tests/src/tests/api/interaction/single-sign-on/happy-path.test.ts b/packages/integration-tests/src/tests/api/interaction/single-sign-on/happy-path.test.ts
index 3ca49d95d..2a8bca01a 100644
--- a/packages/integration-tests/src/tests/api/interaction/single-sign-on/happy-path.test.ts
+++ b/packages/integration-tests/src/tests/api/interaction/single-sign-on/happy-path.test.ts
@@ -1,9 +1,9 @@
-import { InteractionEvent, type SsoConnectorMetadata } from '@logto/schemas';
+import { InteractionEvent, SsoProviderName, type SsoConnectorMetadata } from '@logto/schemas';
import { getSsoAuthorizationUrl, getSsoConnectorsByEmail } from '#src/api/interaction-sso.js';
import { putInteraction } from '#src/api/interaction.js';
import { createSsoConnector, deleteSsoConnectorById } from '#src/api/sso-connector.js';
-import { logtoUrl, SsoProviderName } from '#src/constants.js';
+import { logtoUrl } from '#src/constants.js';
import { initClient } from '#src/helpers/client.js';
describe('Single Sign On Happy Path', () => {
diff --git a/packages/integration-tests/src/tests/api/interaction/single-sign-on/sad-path.test.ts b/packages/integration-tests/src/tests/api/interaction/single-sign-on/sad-path.test.ts
index 4f5a6db50..058975e44 100644
--- a/packages/integration-tests/src/tests/api/interaction/single-sign-on/sad-path.test.ts
+++ b/packages/integration-tests/src/tests/api/interaction/single-sign-on/sad-path.test.ts
@@ -1,4 +1,4 @@
-import { InteractionEvent } from '@logto/schemas';
+import { InteractionEvent, SsoProviderName } from '@logto/schemas';
import {
partialConfigAndProviderNames,
@@ -7,7 +7,6 @@ import {
import { getSsoAuthorizationUrl, postSamlAssertion } from '#src/api/interaction-sso.js';
import { putInteraction } from '#src/api/interaction.js';
import { createSsoConnector, deleteSsoConnectorById } from '#src/api/sso-connector.js';
-import { SsoProviderName } from '#src/constants.js';
import { initClient } from '#src/helpers/client.js';
import { expectRejects } from '#src/helpers/index.js';
diff --git a/packages/integration-tests/src/tests/api/sso-connectors.test.ts b/packages/integration-tests/src/tests/api/sso-connectors.test.ts
index f1969b887..fc8e0d6f8 100644
--- a/packages/integration-tests/src/tests/api/sso-connectors.test.ts
+++ b/packages/integration-tests/src/tests/api/sso-connectors.test.ts
@@ -1,3 +1,5 @@
+import { SsoProviderName } from '@logto/schemas';
+import { conditional } from '@silverhand/essentials';
import { HTTPError } from 'got';
import {
@@ -13,7 +15,6 @@ import {
patchSsoConnectorById,
patchSsoConnectorConfigById,
} from '#src/api/sso-connector.js';
-import { SsoProviderName } from '#src/constants.js';
describe('sso-connector library', () => {
it('should return sso-connector-factories', async () => {
@@ -300,6 +301,33 @@ describe('patch sso-connector config by id', () => {
await deleteSsoConnectorById(id);
});
+ it.each(providerNames)(
+ 'should successfully patch incomplete config if `partialValidateConfig` query parameter is specified',
+ async (providerName) => {
+ const { id } = await createSsoConnector({
+ providerName,
+ connectorName: 'integration_test connector',
+ config: {
+ clientSecret: 'bar',
+ metadataType: 'URL',
+ },
+ });
+
+ await expect(
+ patchSsoConnectorConfigById(
+ id,
+ {
+ ...conditional(providerName === SsoProviderName.OIDC && { issuer: 'issuer' }),
+ ...conditional(providerName === SsoProviderName.SAML && { entityId: 'entity_id' }),
+ },
+ true
+ )
+ ).resolves.not.toThrow();
+
+ await deleteSsoConnectorById(id);
+ }
+ );
+
it.each(partialConfigAndProviderNames)(
'should patch sso connector config',
async ({ providerName, config }) => {
diff --git a/packages/phrases/src/locales/de/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/de/translation/admin-console/enterprise-sso.ts
index f4f158475..7d6e36ccb 100644
--- a/packages/phrases/src/locales/de/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/de/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Name für den Unternehmensidentitätsanbieter',
create_button_text: 'Connector erstellen',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso.ts
index 9a244c83e..042c6977e 100644
--- a/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso.ts
@@ -19,6 +19,56 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Name for the enterprise identity provider',
create_button_text: 'Create connector',
},
+ guide: {
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ title: 'Configure your service in the IdP',
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ title: 'Attribute mappings',
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ col_sp_claims: 'Claim name of Logto',
+ col_idp_claims: 'Claim name of identity provider',
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ title: 'Configure the IdP metadata',
+ description: 'Configure the metadata from the identity provider',
+ dropdown_trigger_text: 'Use another configuration method',
+ dropdown_title: 'select your configuration method',
+ metadata_format_url: 'Enter the metadata URL',
+ metadata_format_xml: 'Upload the metadata XML file',
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ metadata_url_field_name: 'Metadata URL',
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ metadata_xml_field_name: 'Metadata XML file',
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ sign_in_endpoint_field_name: 'Sign on URL',
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ certificate_field_name: 'Signing certificate',
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ client_id_field_name: 'Client ID',
+ client_secret_field_name: 'Client secret',
+ issuer_field_name: 'Issuer',
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/es/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/es/translation/admin-console/enterprise-sso.ts
index 78ae0fb1d..d144d88fb 100644
--- a/packages/phrases/src/locales/es/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/es/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Nombre para el proveedor de identidad empresarial',
create_button_text: 'Crear conector',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/fr/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/fr/translation/admin-console/enterprise-sso.ts
index 3bf924004..1433e7e03 100644
--- a/packages/phrases/src/locales/fr/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/fr/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: "Nom du fournisseur d'identité de l'entreprise",
create_button_text: 'Créer un connecteur',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/it/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/it/translation/admin-console/enterprise-sso.ts
index 982fc1fbc..f8f64c6d1 100644
--- a/packages/phrases/src/locales/it/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/it/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Nome del provider di identità aziendale',
create_button_text: 'Crea connettore',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/ja/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/ja/translation/admin-console/enterprise-sso.ts
index 6ece94aab..330b8dd42 100644
--- a/packages/phrases/src/locales/ja/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/ja/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: '企業向けアイデンティティプロバイダーの名前',
create_button_text: 'コネクターを作成',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/ko/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/ko/translation/admin-console/enterprise-sso.ts
index 6ad0b07f2..29e51a05b 100644
--- a/packages/phrases/src/locales/ko/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/ko/translation/admin-console/enterprise-sso.ts
@@ -19,6 +19,87 @@ const enterprise_sso = {
connector_name_field_placeholder: '기업 신원 공급자의 이름',
create_button_text: '커넥터 생성',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/enterprise-sso.ts
index 76d7953cf..678cb1c5f 100644
--- a/packages/phrases/src/locales/pl-pl/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Nazwa dostawcy tożsamości przedsiębiorstwa',
create_button_text: 'Stwórz łącznik',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/pt-br/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/pt-br/translation/admin-console/enterprise-sso.ts
index 34d315075..be4ec4171 100644
--- a/packages/phrases/src/locales/pt-br/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/pt-br/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Nome do provedor de identidade empresarial',
create_button_text: 'Criar conector',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/enterprise-sso.ts
index 1c0d8d13e..804ab9d1e 100644
--- a/packages/phrases/src/locales/pt-pt/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Nome do provedor de identidade empresarial',
create_button_text: 'Criar conector',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/ru/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/ru/translation/admin-console/enterprise-sso.ts
index b09cedb53..ae8ddd73b 100644
--- a/packages/phrases/src/locales/ru/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/ru/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Имя для поставщика идентификации предприятия',
create_button_text: 'Создать коннектор',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/enterprise-sso.ts
index 776bf3138..bd94d8789 100644
--- a/packages/phrases/src/locales/tr-tr/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/enterprise-sso.ts
@@ -20,6 +20,87 @@ const enterprise_sso = {
connector_name_field_placeholder: 'Kurumsal kimlik sağlayıcı için isim',
create_button_text: 'Bağlayıcı Oluştur',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/enterprise-sso.ts
index ca9fdee61..ca3fae203 100644
--- a/packages/phrases/src/locales/zh-cn/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/enterprise-sso.ts
@@ -19,6 +19,87 @@ const enterprise_sso = {
connector_name_field_placeholder: '企业身份提供者的名称',
create_button_text: '创建连接器',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/zh-hk/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/zh-hk/translation/admin-console/enterprise-sso.ts
index cd3ee3ce6..5edc75fca 100644
--- a/packages/phrases/src/locales/zh-hk/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/zh-hk/translation/admin-console/enterprise-sso.ts
@@ -19,6 +19,87 @@ const enterprise_sso = {
connector_name_field_placeholder: '企業身份提供者的名稱',
create_button_text: '創建連接器',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/phrases/src/locales/zh-tw/translation/admin-console/enterprise-sso.ts b/packages/phrases/src/locales/zh-tw/translation/admin-console/enterprise-sso.ts
index f683859e5..20b9c9040 100644
--- a/packages/phrases/src/locales/zh-tw/translation/admin-console/enterprise-sso.ts
+++ b/packages/phrases/src/locales/zh-tw/translation/admin-console/enterprise-sso.ts
@@ -19,6 +19,87 @@ const enterprise_sso = {
connector_name_field_placeholder: '企業身份提供者的名稱',
create_button_text: '創建連接器',
},
+ guide: {
+ /** UNTRANSLATED */
+ subtitle: 'A step by step guide to connect the enterprise identity provider.',
+ /** UNTRANSLATED */
+ finish_button_text: 'Continue',
+ },
+ basic_info: {
+ /** UNTRANSLATED */
+ title: 'Configure your service in the IdP',
+ /** UNTRANSLATED */
+ description:
+ 'Create a new application integration by SAML 2.0 in your {{name}} identity provider. Then paste the following value to it.',
+ saml: {
+ /** UNTRANSLATED */
+ acs_url_field_name: 'Assertion consumer service URL (Reply URL)',
+ /** UNTRANSLATED */
+ audience_uri_field_name: 'Audience URI (SP Entity ID)',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ redirect_uri_field_name: 'Redirect URI (Callback URL)',
+ },
+ },
+ attribute_mapping: {
+ /** UNTRANSLATED */
+ title: 'Attribute mappings',
+ /** UNTRANSLATED */
+ description:
+ '`id` and `email` are required to sync user profile from IdP. Enter the following claim name and value in your IdP.',
+ /** UNTRANSLATED */
+ col_sp_claims: 'Claim name of Logto',
+ /** UNTRANSLATED */
+ col_idp_claims: 'Claim name of identity provider',
+ /** UNTRANSLATED */
+ idp_claim_tooltip: 'The claim name of the identity provider',
+ },
+ metadata: {
+ /** UNTRANSLATED */
+ title: 'Configure the IdP metadata',
+ /** UNTRANSLATED */
+ description: 'Configure the metadata from the identity provider',
+ /** UNTRANSLATED */
+ dropdown_trigger_text: 'Use another configuration method',
+ /** UNTRANSLATED */
+ dropdown_title: 'select your configuration method',
+ /** UNTRANSLATED */
+ metadata_format_url: 'Enter the metadata URL',
+ /** UNTRANSLATED */
+ metadata_format_xml: 'Upload the metadata XML file',
+ /** UNTRANSLATED */
+ metadata_format_manual: 'Enter metadata details manually',
+ saml: {
+ /** UNTRANSLATED */
+ metadata_url_field_name: 'Metadata URL',
+ /** UNTRANSLATED */
+ metadata_url_description:
+ 'Dynamically fetch data from the metadata URL and keep certificate up to date.',
+ /** UNTRANSLATED */
+ metadata_xml_field_name: 'Metadata XML file',
+ /** UNTRANSLATED */
+ metadata_xml_uploader_text: 'Upload metadata XML file',
+ /** UNTRANSLATED */
+ sign_in_endpoint_field_name: 'Sign on URL',
+ /** UNTRANSLATED */
+ idp_entity_id_field_name: 'IdP entity ID (Issuer)',
+ /** UNTRANSLATED */
+ certificate_field_name: 'Signing certificate',
+ /** UNTRANSLATED */
+ certificate_placeholder: 'Copy and paste the x509 certificate',
+ },
+ oidc: {
+ /** UNTRANSLATED */
+ client_id_field_name: 'Client ID',
+ /** UNTRANSLATED */
+ client_secret_field_name: 'Client secret',
+ /** UNTRANSLATED */
+ issuer_field_name: 'Issuer',
+ /** UNTRANSLATED */
+ scope_field_name: 'Scope',
+ },
+ },
};
export default Object.freeze(enterprise_sso);
diff --git a/packages/schemas/src/types/sso-connector.ts b/packages/schemas/src/types/sso-connector.ts
index 9a1b2aaa8..da3d63d3d 100644
--- a/packages/schemas/src/types/sso-connector.ts
+++ b/packages/schemas/src/types/sso-connector.ts
@@ -1,6 +1,6 @@
import { z } from 'zod';
-import { SsoConnectors } from '../db-entries/sso-connector.js';
+import { SsoConnectors, type SsoConnector } from '../db-entries/sso-connector.js';
/**
* SSO Connector data type that are returned to the experience client for sign-in use.
@@ -14,8 +14,17 @@ export const ssoConnectorMetadataGuard = z.object({
export type SsoConnectorMetadata = z.infer;
+export enum SsoProviderName {
+ OIDC = 'OIDC',
+ SAML = 'SAML',
+}
+
+export type SupportedSsoConnector = Omit & {
+ providerName: SsoProviderName;
+};
+
const ssoConnectorFactoryDetailGuard = z.object({
- providerName: z.string(),
+ providerName: z.nativeEnum(SsoProviderName),
logo: z.string(),
description: z.string(),
});
@@ -29,11 +38,15 @@ export const ssoConnectorFactoriesResponseGuard = z.object({
export type SsoConnectorFactoriesResponse = z.infer;
-export const ssoConnectorWithProviderConfigGuard = SsoConnectors.guard.merge(
- z.object({
- providerLogo: z.string(),
- providerConfig: z.record(z.unknown()).optional(),
- })
-);
+export const ssoConnectorWithProviderConfigGuard = SsoConnectors.guard
+ .omit({ providerName: true })
+ .merge(
+ z.object({
+ providerName: z.nativeEnum(SsoProviderName),
+ providerLogo: z.string(),
+ providerConfig: z.record(z.unknown()).optional(),
+ providerProperties: z.record(z.unknown()).optional(),
+ })
+ );
export type SsoConnectorWithProviderConfig = z.infer;