Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Email Verification for non-Microsoft/Google Emails #9288

Merged
merged 63 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
170e2f6
introduce server-level env var IS_EMAIL_VERIFICATION_REQUIRED that de…
samyakpiya Dec 31, 2024
d1c04c0
feat(auth): link email verification requirement env to client config
samyakpiya Dec 31, 2024
59a3fbb
add user email verification service
samyakpiya Dec 31, 2024
dc142d8
verify email for users coming from workspace invitation link
samyakpiya Dec 31, 2024
13315f8
introduce email-verification to engine/core-modules
samyakpiya Dec 31, 2024
c99074d
tiny fixes and refactor
samyakpiya Jan 1, 2025
71b2f50
feat: implement email verification flow
samyakpiya Jan 3, 2025
30b9af4
feat(auth): implement email verification check after login
samyakpiya Jan 3, 2025
6aa2ca0
move findAvailableWorkspacesByEmail from authService to userWorkspace…
samyakpiya Jan 4, 2025
921c166
implement email verification token validation and resend email verifi…
samyakpiya Jan 4, 2025
faf24ca
create email template for sending email verification link
samyakpiya Jan 4, 2025
36139a2
implement SendEmailVerificationLink email template in EmailVerificati…
samyakpiya Jan 4, 2025
665ff14
fix(greptile): show errorSnackbar if email not provided to handleRese…
samyakpiya Jan 4, 2025
a74b3b6
fix(greptile): replace encodeURI with encodeURIComponent
samyakpiya Jan 4, 2025
c4857bc
fix(greptile): send verification email before generating login token
samyakpiya Jan 4, 2025
a39091a
fix(greptile): make email a required property in VerifyEmailOutput
samyakpiya Jan 4, 2025
eeeede1
fix(greptile): use Promise.all for async token deletion
samyakpiya Jan 4, 2025
c5a7e00
fix(greptile): move expired emailVerificationToken handling to castAp…
samyakpiya Jan 4, 2025
9057181
refactor(auth): move email verification token services to auth/token/…
samyakpiya Jan 4, 2025
1789126
fix(auth): remove double encoding of email parameter
samyakpiya Jan 4, 2025
edec126
fix(auth): remove extra curly brace in handleVerify function
samyakpiya Jan 4, 2025
1dfa82b
fix: remove email domain check for verification
samyakpiya Jan 4, 2025
e9c0114
Merge branch 'main' into feat/8240-email-verification
samyakpiya Jan 4, 2025
c02f91e
fix(greptile): remove redundant EmailVerificationService import
samyakpiya Jan 4, 2025
2a7a9fd
feat: add test cases for VerifyEmail path in useShowAuthModal tests
samyakpiya Jan 5, 2025
0eb33ba
feat(front): add test cases for VerifyEmail path in usePageChangeEffe…
samyakpiya Jan 5, 2025
4a1097a
chore(server): rename emailVerified to isEmailVerified column on user…
samyakpiya Jan 5, 2025
b1d432a
fix(auth): add EmailVerificationService to SignInUpService test depen…
samyakpiya Jan 5, 2025
b4587fc
test(server): fix and improve email verification token service tests
samyakpiya Jan 5, 2025
d5a97ad
test(auth): add email verification service mocks to auth resolver tests
samyakpiya Jan 5, 2025
be50e3e
style(greptile): add aria-labels to twenty-emails footer links for im…
samyakpiya Jan 5, 2025
fa29671
fix(greptile-ci): add email parameter to verify method in useAuth test
samyakpiya Jan 5, 2025
dfd7b33
refactor(auth): reorganize email verification flow
samyakpiya Jan 6, 2025
e6574d1
refactor(auth): simplify email verification flow and improve UX
samyakpiya Jan 6, 2025
141f164
fix(auth): error message blink in verify-email before redirect
samyakpiya Jan 6, 2025
6de9558
feat(auth): add loading state to resend email verification button
samyakpiya Jan 6, 2025
fa35222
fix(test): add MemoryRouter to useAuth tests for router context
samyakpiya Jan 6, 2025
7072647
feat(email-verification): add rate limiting for verification email re…
samyakpiya Jan 6, 2025
e97a3a9
fix(front): handle empty workspace name in sign-in page
samyakpiya Jan 6, 2025
c8f9856
fix(front): improve email verification error handling
samyakpiya Jan 6, 2025
b49c7ef
refactor(auth): simplify email verification flow
samyakpiya Jan 7, 2025
f521b87
feat(auth): implement token hashing for email verification
samyakpiya Jan 7, 2025
abafb91
fix(auth): failing tests
samyakpiya Jan 7, 2025
dc28892
reafactor(auth): set default email verification token expiry time to 1h
samyakpiya Jan 7, 2025
04ba2a0
fix(greptile-style): add email format validation to resend-email-veri…
samyakpiya Jan 7, 2025
bbffad8
fix(email-verification): return early if verification not requireda
samyakpiya Jan 7, 2025
324c02b
docs: add email verification environment variables documentation
samyakpiya Jan 9, 2025
9e5c563
fix(auth): remove redundant null check in useAuth verify flow
samyakpiya Jan 14, 2025
423215e
refactor(auth): use workspace validator in auth resolver
samyakpiya Jan 14, 2025
5545c52
fix(email-verification): use origin header to determine workspace for…
samyakpiya Jan 14, 2025
87f4ee3
feat(front): show auth modal on VerifyEmail page when logged in
samyakpiya Jan 15, 2025
183a1f4
fix: update test cases for VerifyEmail path in useShowAuthModal tests
samyakpiya Jan 15, 2025
249215f
Merge remote-tracking branch 'origin/main' into feat/8240-email-verif…
AMoreaux Jan 15, 2025
1baa030
Fix conflict
AMoreaux Jan 15, 2025
64d25ed
feat(snack-bar): add deduplication support for notifications
AMoreaux Jan 15, 2025
bf7dd78
feat(snack-bar): add typing to setSnackBarQueue parameter
AMoreaux Jan 15, 2025
a9b173e
Merge remote-tracking branch 'origin/main' into feat/8240-email-verif…
AMoreaux Jan 15, 2025
4970205
Add same dedupe key since request is thrown twice
FelixMalfait Jan 15, 2025
95fc234
refactor(auth): streamline service dependencies
AMoreaux Jan 15, 2025
7d3f3de
Merge remote-tracking branch 'samyakpiya/feat/8240-email-verification…
AMoreaux Jan 15, 2025
db4a9f3
Merge branch 'main' into feat/8240-email-verification
AMoreaux Jan 15, 2025
028f2ad
Merge branch 'main' into feat/8240-email-verification
AMoreaux Jan 15, 2025
5f8d2b5
Merge branch 'main' into feat/8240-email-verification
AMoreaux Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions packages/twenty-emails/src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Column, Row } from '@react-email/components';
import { Link } from 'src/components/Link';
import { ShadowText } from 'src/components/ShadowText';

export const Footer = () => {
return (
<>
<Row>
samyakpiya marked this conversation as resolved.
Show resolved Hide resolved
<Column>
<ShadowText>
<Link
href="https://twenty.com/"
value="Website"
aria-label="Visit Twenty's website"
/>
</ShadowText>
</Column>
<Column>
<ShadowText>
<Link
href="https://github.com/twentyhq/twenty"
value="Github"
aria-label="Visit Twenty's GitHub repository"
/>
</ShadowText>
</Column>
<Column>
<ShadowText>
<Link
href="https://twenty.com/user-guide"
value="User guide"
aria-label="Read Twenty's user guide"
/>
</ShadowText>
</Column>
<Column>
<ShadowText>
<Link
href="https://docs.twenty.com/"
value="Developers"
aria-label="Visit Twenty's developer documentation"
/>
</ShadowText>
</Column>
</Row>
<ShadowText>
Twenty.com Public Benefit Corporation
<br />
2261 Market Street #5275
<br />
San Francisco, CA 94114
</ShadowText>
</>
);
};
35 changes: 3 additions & 32 deletions packages/twenty-emails/src/components/WhatIsTwenty.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Column, Row } from '@react-email/components';
import { Link } from 'src/components/Link';
import { Footer } from 'src/components/Footer';
import { MainText } from 'src/components/MainText';
import { ShadowText } from 'src/components/ShadowText';
import { SubTitle } from 'src/components/SubTitle';

export const WhatIsTwenty = () => {
return (
<>
Expand All @@ -11,35 +10,7 @@ export const WhatIsTwenty = () => {
It's a CRM, a software to help businesses manage their customer data and
relationships efficiently.
</MainText>
<Row>
<Column>
<ShadowText>
<Link href="https://twenty.com/" value="Website" />
</ShadowText>
</Column>
<Column>
<ShadowText>
<Link href="https://github.com/twentyhq/twenty" value="Github" />
</ShadowText>
</Column>
<Column>
<ShadowText>
<Link href="https://twenty.com/user-guide" value="User guide" />
</ShadowText>
</Column>
<Column>
<ShadowText>
<Link href="https://docs.twenty.com/" value="Developers" />
</ShadowText>
</Column>
</Row>
<ShadowText>
Twenty.com Public Benefit Corporation
<br />
2261 Market Street #5275
<br />
San Francisco, CA 94114
</ShadowText>
<Footer />
</>
samyakpiya marked this conversation as resolved.
Show resolved Hide resolved
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { BaseEmail } from 'src/components/BaseEmail';
import { CallToAction } from 'src/components/CallToAction';
import { Footer } from 'src/components/Footer';
import { MainText } from 'src/components/MainText';
import { Title } from 'src/components/Title';

type SendEmailVerificationLinkEmailProps = {
link: string;
};

export const SendEmailVerificationLinkEmail = ({
link,
}: SendEmailVerificationLinkEmailProps) => {
return (
<BaseEmail width={333}>
<Title value="Confirm your email address" />
<CallToAction href={link} value="Verify Email" />
<br />
<br />
<MainText>
Thanks for registering for an account on Twenty! Before we get started,
we just need to confirm that this is you. Click above to verify your
email address.
</MainText>
<Footer />
</BaseEmail>
);
};
1 change: 1 addition & 0 deletions packages/twenty-emails/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './emails/clean-inactive-workspaces.email';
export * from './emails/delete-inactive-workspaces.email';
export * from './emails/password-reset-link.email';
export * from './emails/password-update-notify.email';
export * from './emails/send-email-verification-link.email';
export * from './emails/send-invite-link.email';
23 changes: 21 additions & 2 deletions packages/twenty-front/src/generated-metadata/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export type ClientConfig = {
debugMode: Scalars['Boolean']['output'];
defaultSubdomain?: Maybe<Scalars['String']['output']>;
frontDomain: Scalars['String']['output'];
isEmailVerificationRequired: Scalars['Boolean']['output'];
isMultiWorkspaceEnabled: Scalars['Boolean']['output'];
isSSOEnabled: Scalars['Boolean']['output'];
sentry: Sentry;
Expand Down Expand Up @@ -404,7 +405,6 @@ export enum FeatureFlagKey {
IsSsoEnabled = 'IsSSOEnabled',
IsStripeIntegrationEnabled = 'IsStripeIntegrationEnabled',
IsUniqueIndexesEnabled = 'IsUniqueIndexesEnabled',
IsViewGroupsEnabled = 'IsViewGroupsEnabled',
Copy link
Member

@FelixMalfait FelixMalfait Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b71246b this was brought back (regenerate graphql before merging)

IsWorkflowEnabled = 'IsWorkflowEnabled'
}

Expand Down Expand Up @@ -612,9 +612,11 @@ export type Mutation = {
generateApiKeyToken: ApiKeyToken;
generateTransientToken: TransientToken;
getAuthorizationUrl: GetAuthorizationUrlOutput;
getLoginTokenFromEmailVerificationToken: LoginToken;
impersonate: ImpersonateOutput;
publishServerlessFunction: ServerlessFunction;
renewToken: AuthTokens;
resendEmailVerificationToken: ResendEmailVerificationTokenOutput;
resendWorkspaceInvitation: SendInvitationsOutput;
runWorkflowVersion: WorkflowRun;
sendInvitations: SendInvitationsOutput;
Expand Down Expand Up @@ -811,6 +813,12 @@ export type MutationGetAuthorizationUrlArgs = {
};


export type MutationGetLoginTokenFromEmailVerificationTokenArgs = {
captchaToken?: InputMaybe<Scalars['String']['input']>;
emailVerificationToken: Scalars['String']['input'];
};


export type MutationImpersonateArgs = {
userId: Scalars['String']['input'];
workspaceId: Scalars['String']['input'];
Expand All @@ -827,6 +835,11 @@ export type MutationRenewTokenArgs = {
};


export type MutationResendEmailVerificationTokenArgs = {
email: Scalars['String']['input'];
};


export type MutationResendWorkspaceInvitationArgs = {
appTokenId: Scalars['String']['input'];
};
Expand Down Expand Up @@ -1289,6 +1302,11 @@ export enum RemoteTableStatus {
Synced = 'SYNCED'
}

export type ResendEmailVerificationTokenOutput = {
__typename?: 'ResendEmailVerificationTokenOutput';
success: Scalars['Boolean']['output'];
};

export type RunWorkflowVersionInput = {
/** Execution result in JSON format */
payload?: InputMaybe<Scalars['JSON']['input']>;
Expand Down Expand Up @@ -1631,9 +1649,9 @@ export type User = {
deletedAt?: Maybe<Scalars['DateTime']['output']>;
disabled?: Maybe<Scalars['Boolean']['output']>;
email: Scalars['String']['output'];
emailVerified: Scalars['Boolean']['output'];
firstName: Scalars['String']['output'];
id: Scalars['UUID']['output'];
isEmailVerified: Scalars['Boolean']['output'];
lastName: Scalars['String']['output'];
onboardingStatus?: Maybe<OnboardingStatus>;
passwordHash?: Maybe<Scalars['String']['output']>;
Expand All @@ -1657,6 +1675,7 @@ export type UserExists = {
__typename?: 'UserExists';
availableWorkspaces: Array<AvailableWorkspaceOutput>;
exists: Scalars['Boolean']['output'];
isEmailVerified: Scalars['Boolean']['output'];
};

export type UserExistsOutput = UserExists | UserNotExists;
Expand Down
Loading
Loading