Fix email not verified issue while login through sso (#13631)

In this PR:
- fix race condition while getting token and redirecting to workspace
domain (missing await)
- add userFriendlyMessage when user does not have password and we try to
log in using password
- refactor computePartialUserFromUserPayload to remove side effect
- add isEmailAlreadyVerified in userPayload that will set
user.isEmailVerified to true
This commit is contained in:
Charles Bochet
2025-08-05 14:01:55 +02:00
committed by GitHub
parent dcded4ae4f
commit 16d78b450c
5 changed files with 29 additions and 15 deletions
@@ -5,6 +5,7 @@ import { ApolloError } from '@apollo/client';
import { verifyEmailRedirectPathState } from '@/app/states/verifyEmailRedirectPathState';
import { useVerifyLogin } from '@/auth/hooks/useVerifyLogin';
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { useLingui } from '@lingui/react/macro';
@@ -15,7 +16,6 @@ import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
import { EmailVerificationSent } from '../sign-in-up/components/EmailVerificationSent';
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
export const VerifyEmailEffect = () => {
const {
@@ -90,7 +90,7 @@ export const VerifyEmailEffect = () => {
setVerifyEmailRedirectPath(verifyEmailRedirectPath);
}
return verifyLoginToken(loginToken.token);
await verifyLoginToken(loginToken.token);
} catch (error) {
enqueueErrorSnackBar({
...(error instanceof ApolloError
@@ -11,8 +11,8 @@ export const useSignUpInNewWorkspace = () => {
const [signUpInNewWorkspaceMutation] = useSignUpInNewWorkspaceMutation();
const createWorkspace = ({ newTab } = { newTab: true }) => {
signUpInNewWorkspaceMutation({
const createWorkspace = async ({ newTab } = { newTab: true }) => {
await signUpInNewWorkspaceMutation({
onCompleted: async (data) => {
return await redirectToWorkspaceDomain(
getWorkspaceUrl(data.signUpInNewWorkspace.workspace.workspaceUrls),
@@ -159,6 +159,9 @@ export class AuthService {
throw new AuthException(
'Incorrect login method',
AuthExceptionCode.INVALID_INPUT,
{
userFriendlyMessage: t`User was not created with email/password`,
},
);
}
@@ -239,7 +242,7 @@ export class AuthService {
if (params.userData.type === 'newUser') {
const partialUserWithPicture =
await this.signInUpService.computeParamsForNewUser(
await this.signInUpService.computePartialUserFromUserPayload(
params.userData.newUserPayload,
params.authParams,
);
@@ -725,6 +728,7 @@ export class AuthService {
lastName,
email,
picture,
isEmailAlreadyVerified: true,
},
{
provider: authProvider,
@@ -780,6 +784,7 @@ export class AuthService {
email,
picture,
locale,
isEmailAlreadyVerified: true,
},
existingUser,
);
@@ -57,14 +57,11 @@ export class SignInUpService {
private readonly userService: UserService,
) {}
async computeParamsForNewUser(
newUserParams: SignInUpNewUserPayload,
async computePartialUserFromUserPayload(
newUserPayload: SignInUpNewUserPayload,
authParams: AuthProviderWithPasswordType['authParams'],
) {
if (!newUserParams.firstName) newUserParams.firstName = '';
if (!newUserParams.lastName) newUserParams.lastName = '';
if (!newUserParams?.email) {
): Promise<PartialUserWithPicture> {
if (!newUserPayload?.email) {
throw new AuthException(
'Email is required',
AuthExceptionCode.INVALID_INPUT,
@@ -74,11 +71,22 @@ export class SignInUpService {
);
}
const partialNewUser: PartialUserWithPicture = {
email: newUserPayload.email,
firstName: newUserPayload.firstName ?? '',
lastName: newUserPayload.lastName ?? '',
picture: newUserPayload.picture ?? '',
locale: newUserPayload.locale ?? 'en',
isEmailVerified: newUserPayload.isEmailAlreadyVerified,
};
if (authParams.provider === AuthProviderEnum.Password) {
newUserParams.passwordHash = await this.generateHash(authParams.password);
partialNewUser.passwordHash = await this.generateHash(
authParams.password,
);
}
return newUserParams as PartialUserWithPicture;
return partialNewUser;
}
async signInUp(
@@ -428,7 +436,7 @@ export class SignInUpService {
authParams: AuthProviderWithPasswordType['authParams'],
) {
return this.saveNewUser(
await this.computeParamsForNewUser(newUserParams, authParams),
await this.computePartialUserFromUserPayload(newUserParams, authParams),
await this.setDefaultImpersonateAndAccessFullAdminPanel(),
);
}
@@ -23,6 +23,7 @@ export type SignInUpNewUserPayload = {
picture?: string | null;
passwordHash?: string | null;
locale?: keyof typeof APP_LOCALES | null;
isEmailAlreadyVerified?: boolean;
};
export type PartialUserWithPicture = {