0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

chore: remove dev feature guard (#6808)

* chore: remove dev feature guard

remove dev feature guard

* chore: add changesets

add changesets
This commit is contained in:
simeng-li 2024-11-15 11:17:22 +08:00 committed by GitHub
parent 06a1bd1394
commit 640425414f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 63 additions and 37 deletions

View file

@ -0,0 +1,16 @@
---
"@logto/console": minor
"@logto/core": minor
"@logto/phrases": minor
---
add `trustUnverifiedEmail` setting for the Microsoft EntraID OIDC SSO connector
Since we launched the **EntraID OIDC SSO connector** we have received several feedbacks that their customer's email address can not be populated to Logto's user profile when signing up through the EntraID OIDC SSO connector.
This is because Logto only syncs verified email addresses, meaning the `email_verified` claim must be `true` in the user info response from the OIDC provider.
However, based on Microsoft's documentation, since the user's email address in manually managed by the organization, they are not verified guaranteed. This means that the `email_verified` claim will not be included in their user info response.
To address this issue, we have added a new `trustUnverifiedEmail` exclusively for the Microsoft EntraID OIDC SSO connector. When this setting is enabled, Logto will trust the email address provided by the Microsoft EntraID OIDC SSO connector even if the `email_verified` claim is not included in the user info response. This will allow users to sign up and log in to Logto using their email address without any issues. Please note this may introduce a security risk as the email address is not verified by the OIDC provider. You should only enable this setting if you trust the email address provided by the Microsoft EntraID OIDC SSO connector.
You can configure this setting in the **EntraID OIDC SSO connector** settings page in the Logto console or through the management API.

View file

@ -0,0 +1,15 @@
---
"@logto/console": minor
"@logto/core": minor
"@logto/experience": minor
"@logto/experience-legacy": minor
"@logto/phrases": minor
"@logto/phrases-experience": minor
"@logto/schemas": minor
---
display support email and website info on experience error pages.
Added support email and website info to the error pages of the experience app. E.g. when a user tries to access a page that doesn't exist, or when the social session is not found in a social callback page. This will help users to contact support easily when they encounter an error.
You may configure the support email and website info in the sign-in experience settings page in the Logto console or through the management API.

View file

@ -0,0 +1,12 @@
---
"@logto/console": minor
"@logto/core": minor
"@logto/phrases": minor
"@logto/schemas": minor
---
add unknown session redirect url in the sign-in experience settings
In certain cases, Logto may be unable to properly identify a users authentication session when they land on the sign-in page. This can happen if the session has expired, if the user bookmarks the sign-in URL for future access, or if they directly share the sign-in link. By default, an "unknown session" 404 error is displayed.
To improve user experience, we have added a new `unknownSessionRedirectUrl` field in the sign-in experience settings.You can configure this field to redirect users to a custom URL when an unknown session is detected. This will help users to easily navigate to your client application or website and reinitiate the authentication process automatically.

View file

@ -2,7 +2,6 @@ import { SsoProviderName } from '@logto/schemas';
import { useFormContext } from 'react-hook-form'; import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { isDevFeaturesEnabled } from '@/consts/env';
import CopyToClipboard from '@/ds-components/CopyToClipboard'; import CopyToClipboard from '@/ds-components/CopyToClipboard';
import FormField from '@/ds-components/FormField'; import FormField from '@/ds-components/FormField';
import InlineNotification from '@/ds-components/InlineNotification'; import InlineNotification from '@/ds-components/InlineNotification';
@ -85,7 +84,7 @@ function OidcMetadataForm({ providerConfig, config, providerName }: Props) {
<FormField title="enterprise_sso.metadata.oidc.scope_field_name"> <FormField title="enterprise_sso.metadata.oidc.scope_field_name">
<TextInput {...register('scope')} error={Boolean(errors.scope)} /> <TextInput {...register('scope')} error={Boolean(errors.scope)} />
</FormField> </FormField>
{isDevFeaturesEnabled && providerName === SsoProviderName.AZURE_AD_OIDC && ( {providerName === SsoProviderName.AZURE_AD_OIDC && (
<FormField <FormField
title="enterprise_sso_details.trust_unverified_email" title="enterprise_sso_details.trust_unverified_email"
tip={t('enterprise_sso_details.trust_unverified_email_tip')} tip={t('enterprise_sso_details.trust_unverified_email_tip')}

View file

@ -1,5 +1,4 @@
import PageMeta from '@/components/PageMeta'; import PageMeta from '@/components/PageMeta';
import { isDevFeaturesEnabled } from '@/consts/env';
import SignInExperienceTabWrapper from '../components/SignInExperienceTabWrapper'; import SignInExperienceTabWrapper from '../components/SignInExperienceTabWrapper';
@ -16,7 +15,7 @@ function Content({ isActive }: Props) {
<SignInExperienceTabWrapper isActive={isActive}> <SignInExperienceTabWrapper isActive={isActive}>
{isActive && <PageMeta titleKey={['sign_in_exp.tabs.content', 'sign_in_exp.page_title']} />} {isActive && <PageMeta titleKey={['sign_in_exp.tabs.content', 'sign_in_exp.page_title']} />}
<TermsForm /> <TermsForm />
{isDevFeaturesEnabled && <SupportForm />} <SupportForm />
<LanguagesForm isManageLanguageVisible /> <LanguagesForm isManageLanguageVisible />
</SignInExperienceTabWrapper> </SignInExperienceTabWrapper>
); );

View file

@ -1,7 +1,6 @@
import { useFormContext } from 'react-hook-form'; import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { isDevFeaturesEnabled } from '@/consts/env';
import Card from '@/ds-components/Card'; import Card from '@/ds-components/Card';
import FormField from '@/ds-components/FormField'; import FormField from '@/ds-components/FormField';
import Switch from '@/ds-components/Switch'; import Switch from '@/ds-components/Switch';
@ -49,22 +48,18 @@ function AdvancedOptions() {
)} )}
/> />
</FormField> </FormField>
{isDevFeaturesEnabled && ( <FormField
<FormField title="sign_in_exp.sign_up_and_sign_in.advanced_options.unknown_session_redirect_url"
title="sign_in_exp.sign_up_and_sign_in.advanced_options.unknown_session_redirect_url" tip={t('sign_in_exp.sign_up_and_sign_in.advanced_options.unknown_session_redirect_url_tip')}
tip={t( >
'sign_in_exp.sign_up_and_sign_in.advanced_options.unknown_session_redirect_url_tip' <TextInput
)} {...register('unknownSessionRedirectUrl', {
> validate: (value) => !value || uriValidator(value) || t('errors.invalid_uri_format'),
<TextInput })}
{...register('unknownSessionRedirectUrl', { error={errors.unknownSessionRedirectUrl?.message}
validate: (value) => !value || uriValidator(value) || t('errors.invalid_uri_format'), placeholder="https://"
})} />
error={errors.unknownSessionRedirectUrl?.message} </FormField>
placeholder="https://"
/>
</FormField>
)}
</Card> </Card>
); );
} }

View file

@ -96,11 +96,6 @@ describe('koaSpaSessionGuard', () => {
} }
it('should redirect to configured unknown session redirect URL in SIE if session not found for a selected path', async () => { it('should redirect to configured unknown session redirect URL in SIE if session not found for a selected path', async () => {
const stub = Sinon.stub(EnvSet, 'values').value({
...EnvSet.values,
isDevFeaturesEnabled: true,
});
const unknownSessionRedirectUrl = 'https://foo.bar/redirect'; const unknownSessionRedirectUrl = 'https://foo.bar/redirect';
interactionDetails.mockRejectedValue(new Error('session not found')); interactionDetails.mockRejectedValue(new Error('session not found'));
@ -113,8 +108,6 @@ describe('koaSpaSessionGuard', () => {
}); });
await koaSpaSessionGuard(provider, queries)(ctx, next); await koaSpaSessionGuard(provider, queries)(ctx, next);
expect(ctx.redirect).toBeCalledWith(unknownSessionRedirectUrl); expect(ctx.redirect).toBeCalledWith(unknownSessionRedirectUrl);
stub.restore();
}); });
it('should redirect to configured URL if session not found for a selected path', async () => { it('should redirect to configured URL if session not found for a selected path', async () => {

View file

@ -37,17 +37,14 @@ export default function koaSpaSessionGuard<
try { try {
await provider.interactionDetails(ctx.req, ctx.res); await provider.interactionDetails(ctx.req, ctx.res);
} catch { } catch {
// TODO: remove this check after the feature is stable // For unknown session, check if there is a redirect URL set in the SignInExperience
if (EnvSet.values.isDevFeaturesEnabled) { const { unknownSessionRedirectUrl } =
// For unknown session, check if there is a redirect URL set in the SignInExperience await queries.signInExperiences.findDefaultSignInExperience();
const { unknownSessionRedirectUrl } =
await queries.signInExperiences.findDefaultSignInExperience();
if (unknownSessionRedirectUrl) { if (unknownSessionRedirectUrl) {
ctx.redirect(unknownSessionRedirectUrl); ctx.redirect(unknownSessionRedirectUrl);
return; return;
}
} }
// If not, check if there is a redirect URL set in the tenant level LogtoConfigs // If not, check if there is a redirect URL set in the tenant level LogtoConfigs