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

feat(authenticator): add angular support for email mfa #6356

Merged
merged 53 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
042aee7
feat: add email mfa support to state machine
jjarvisp Jan 27, 2025
6b796dd
refactor: facade types
jjarvisp Jan 27, 2025
e6a0473
refactor: update facade types
jjarvisp Jan 27, 2025
8da9d38
test: update react core tests to align with type changes
jjarvisp Jan 28, 2025
859c353
refactor: generalize radio options
jjarvisp Jan 28, 2025
edefdb0
refactor: update react-core-auth tests
jjarvisp Jan 28, 2025
6a0bf4c
refactor: update vue test spec
jjarvisp Jan 28, 2025
3dd8e97
chore: add addtnl challenge names
jjarvisp Jan 28, 2025
6497bd2
Merge branch 'feat-email-mfa/main' into james/feat-email-mfa/update-s…
jjarvisp Jan 28, 2025
a379df3
chore: quick changes
jjarvisp Jan 29, 2025
274252c
fix: allow labelled radio options
jjarvisp Jan 31, 2025
31ae03b
chore: add i18n setup
jjarvisp Jan 31, 2025
6295fa8
test: update textUtil tests
jjarvisp Jan 31, 2025
0bcace6
chore: type safe MFA types
jjarvisp Jan 31, 2025
cc749cf
fix: add addtl text utils
jjarvisp Feb 11, 2025
28db8e6
chore: add translation sites
jjarvisp Feb 18, 2025
d55d2e0
chore: alphabetization
jjarvisp Feb 18, 2025
7e51784
chore: alphabetization
jjarvisp Feb 18, 2025
88039f1
chore: remove comment
jjarvisp Feb 18, 2025
830d3ea
chore: alphabetization
jjarvisp Feb 18, 2025
255403b
chore: alphabetization
jjarvisp Feb 18, 2025
9f70329
chore: address feedback
jjarvisp Feb 21, 2025
ba0aa21
chore: address feedback
jjarvisp Feb 21, 2025
d9ea3a6
chore: alphabetization
jjarvisp Feb 21, 2025
3548468
chore: add email mfa env / example route
jjarvisp Jan 27, 2025
353c175
feat: adding react support for email mfa
jjarvisp Jan 28, 2025
f3bc045
chore: update env to gen2 path
jjarvisp Jan 28, 2025
78202f1
fix: add validation errors to radio group
jjarvisp Jan 29, 2025
3bb5722
chore: initial state is sign in
jjarvisp Jan 31, 2025
e60b6f1
feat: enable autoSignIn as state machine service
jjarvisp Jan 29, 2025
39f25c9
chore: add email mfa examples
jjarvisp Jan 29, 2025
230a3ca
feat: adding email mfa test specs
jjarvisp Jan 29, 2025
8c26545
chore: default state is sign in
jjarvisp Jan 31, 2025
8cb6cb8
chore: update react-core tests
jjarvisp Jan 31, 2025
fcdc880
fix: allow labelled radio options
jjarvisp Jan 31, 2025
1dea23d
chore: tmp RN type fix
jjarvisp Jan 31, 2025
05facb5
chore: update component to use text util
jjarvisp Jan 31, 2025
a69c7f9
test: update react e2e and unit tests
jjarvisp Feb 11, 2025
8b4876c
fix: avoid mutate xstate context
jjarvisp Feb 11, 2025
de9956d
chore: add missing unit tests
jjarvisp Feb 17, 2025
f69c422
chore: address feedback
jjarvisp Feb 22, 2025
d17021c
chore: address feedback
jjarvisp Feb 25, 2025
189cfc8
chore: address feedback
jjarvisp Feb 26, 2025
f62d141
chore: address feedback
jjarvisp Feb 26, 2025
c067f12
chore: add angular email mfa example apps
jjarvisp Feb 13, 2025
1553db4
chore: add radio field component
jjarvisp Feb 15, 2025
b690208
feat: add email mfa screens
jjarvisp Feb 15, 2025
7d9190c
test: add email mfa e2e tests
jjarvisp Feb 15, 2025
18f5ea6
chore: use default classNames
jjarvisp Feb 15, 2025
f9b5c24
chore: address feedback
jjarvisp Feb 23, 2025
f8b63a0
chore: address feedback
jjarvisp Feb 26, 2025
2bdcc03
chore: fix slot names
jjarvisp Feb 28, 2025
d19b908
Merge branch 'feat-email-mfa/main' into james/feat-email-mfa/angular-…
jjarvisp Feb 28, 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
15 changes: 15 additions & 0 deletions examples/angular/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import { SignUpWithPhoneComponent } from 'src/pages/ui/components/authenticator/
import { SignUpWithUsernameComponent } from 'src/pages/ui/components/authenticator/sign-up-with-username/sign-up-with-username.component';
import { UseAuthenticatorComponent } from 'src/pages/ui/components/authenticator/useAuthenticator/useAuthenticator.component';
import { UseAuthenticatorHomeComponent } from 'src/pages/ui/components/authenticator/useAuthenticator/home/useAuthenticatorHome.component';
import { SignInWithEmailMfaComponent } from 'src/pages/ui/components/authenticator/sign-in-with-email-mfa/sign-in-with-email-mfa.component';
import { SignInWithEmailMfaSelectionComponent } from 'src/pages/ui/components/authenticator/sign-in-with-email-mfa-selection/sign-in-with-email-mfa-selection.component';
import { SignInWithEmailMfaSetupSelectionComponent } from 'src/pages/ui/components/authenticator/sign-in-with-email-mfa-setup-selection/sign-in-with-email-mfa-setup-selection.component';

const routes: Routes = [
{
Expand Down Expand Up @@ -117,6 +120,18 @@ const routes: Routes = [
path: 'ui/components/authenticator/useAuthenticator/home',
component: UseAuthenticatorHomeComponent,
},
{
path: 'ui/components/authenticator/sign-in-with-email-mfa',
component: SignInWithEmailMfaComponent,
},
{
path: 'ui/components/authenticator/sign-in-with-email-mfa-selection',
component: SignInWithEmailMfaSelectionComponent,
},
{
path: 'ui/components/authenticator/sign-in-with-email-mfa-setup-selection',
component: SignInWithEmailMfaSetupSelectionComponent,
},
];

@NgModule({
Expand Down
6 changes: 6 additions & 0 deletions examples/angular/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import { SignUpWithPhoneComponent } from 'src/pages/ui/components/authenticator/
import { SignUpWithUsernameComponent } from 'src/pages/ui/components/authenticator/sign-up-with-username/sign-up-with-username.component';
import { UseAuthenticatorComponent } from 'src/pages/ui/components/authenticator/useAuthenticator/useAuthenticator.component';
import { UseAuthenticatorHomeComponent } from 'src/pages/ui/components/authenticator/useAuthenticator/home/useAuthenticatorHome.component';
import { SignInWithEmailMfaComponent } from 'src/pages/ui/components/authenticator/sign-in-with-email-mfa/sign-in-with-email-mfa.component';
import { SignInWithEmailMfaSelectionComponent } from 'src/pages/ui/components/authenticator/sign-in-with-email-mfa-selection/sign-in-with-email-mfa-selection.component';
import { SignInWithEmailMfaSetupSelectionComponent } from 'src/pages/ui/components/authenticator/sign-in-with-email-mfa-setup-selection/sign-in-with-email-mfa-setup-selection.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -55,6 +58,9 @@ import { UseAuthenticatorHomeComponent } from 'src/pages/ui/components/authentic
SignUpWithUsernameComponent,
UseAuthenticatorComponent,
UseAuthenticatorHomeComponent,
SignInWithEmailMfaComponent,
SignInWithEmailMfaSelectionComponent,
SignInWithEmailMfaSetupSelectionComponent,
],
imports: [
BrowserModule,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import awsExports from '@environments/auth/gen2/auth-with-email-mfa/amplify_outputs.json';
export default awsExports;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<amplify-authenticator [services]="services">
<ng-template
amplifySlot="authenticated"
let-user="user"
let-signOut="signOut"
>
<h2>Welcome, {{ user.username }}!</h2>
<button (click)="signOut()">Sign Out</button>
</ng-template>
</amplify-authenticator>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Component, OnInit } from '@angular/core';
import { Amplify } from 'aws-amplify';
import { AuthenticatorComponent } from '@aws-amplify/ui-angular';

import awsExports from './aws-exports';

@Component({
selector: 'app-sign-in-with-email-mfa-selection',
templateUrl: './sign-in-with-email-mfa-selection.component.html',
})
export class SignInWithEmailMfaSelectionComponent implements OnInit {
public services: AuthenticatorComponent['services'] = {
handleSignIn: async () => {
return {
isSignedIn: false,
nextStep: {
signInStep: 'CONTINUE_SIGN_IN_WITH_MFA_SELECTION',
allowedMFATypes: ['EMAIL', 'TOTP'],
},
};
},
handleConfirmSignIn: async ({ challengeResponse }) => {
if (challengeResponse === 'EMAIL') {
return {
isSignedIn: false,
nextStep: {
signInStep: 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE',
codeDeliveryDetails: {
destination: 'a***@e***.com',
deliveryMedium: 'EMAIL',
attributeName: 'email',
},
},
};
}

if (challengeResponse === '123456') {
return {
isSignedIn: true,
nextStep: {
signInStep: 'DONE',
},
};
}
throw new Error('Invalid code or auth state for the user.');
},
getCurrentUser: async () => {
return {
userId: '******************',
username: 'james',
};
},
};

constructor() {
Amplify.configure(awsExports);
}

ngOnInit(): void {}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import awsExports from '@environments/auth/gen2/auth-with-email-mfa/amplify_outputs.json';
export default awsExports;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<amplify-authenticator [services]="services">
<ng-template
amplifySlot="authenticated"
let-user="user"
let-signOut="signOut"
>
<h2>Welcome, {{ user.username }}!</h2>
<button (click)="signOut()">Sign Out</button>
</ng-template>
</amplify-authenticator>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Component, OnInit } from '@angular/core';
import { Amplify } from 'aws-amplify';
import { AuthenticatorComponent } from '@aws-amplify/ui-angular';

import awsExports from './aws-exports';

@Component({
selector: 'app-sign-in-with-email-mfa-setup-selection',
templateUrl: './sign-in-with-email-mfa-setup-selection.component.html',
})
export class SignInWithEmailMfaSetupSelectionComponent implements OnInit {
public services: AuthenticatorComponent['services'] = {
handleSignIn: async () => {
return {
isSignedIn: false,
nextStep: {
signInStep: 'CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION',
allowedMFATypes: ['EMAIL', 'TOTP'],
},
};
},
handleConfirmSignIn: async ({ challengeResponse }) => {
if (challengeResponse === 'EMAIL') {
return {
isSignedIn: false,
nextStep: {
signInStep: 'CONTINUE_SIGN_IN_WITH_EMAIL_SETUP',
},
};
}
if (challengeResponse.includes('@example.com')) {
return {
isSignedIn: false,
nextStep: {
signInStep: 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE',
codeDeliveryDetails: {
destination: 'a***@e***.com',
deliveryMedium: 'EMAIL',
attributeName: 'email',
},
},
};
}
if (challengeResponse === '123456') {
return {
isSignedIn: true,
nextStep: {
signInStep: 'DONE',
},
};
}
throw new Error('Invalid code or auth state for the user.');
},
getCurrentUser: async () => {
return {
userId: '******************',
username: 'james',
};
},
};

constructor() {
Amplify.configure(awsExports);
}

ngOnInit(): void {}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import awsExports from '@environments/auth/gen2/auth-with-email-mfa/amplify_outputs.json';
export default awsExports;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<amplify-authenticator [services]="services">
<ng-template
amplifySlot="authenticated"
let-user="user"
let-signOut="signOut"
>
<h2>Welcome, {{ user.username }}!</h2>
<button (click)="signOut()">Sign Out</button>
</ng-template>
</amplify-authenticator>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Component } from '@angular/core';
import { Amplify } from 'aws-amplify';
import { AuthenticatorComponent } from '@aws-amplify/ui-angular';

import awsExports from './aws-exports';

@Component({
selector: 'app-sign-in-with-email-mfa',
templateUrl: './sign-in-with-email-mfa.component.html',
})
export class SignInWithEmailMfaComponent {
public services: AuthenticatorComponent['services'] = {
handleSignIn: async () => {
return {
isSignedIn: false,
nextStep: {
signInStep: 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE',
codeDeliveryDetails: {
destination: 'a***@e***.com',
deliveryMedium: 'EMAIL',
attributeName: 'email',
},
},
};
},
handleConfirmSignIn: async ({ challengeResponse }) => {
if (challengeResponse === '123456') {
return {
isSignedIn: true,
nextStep: {
signInStep: 'DONE',
},
};
}
throw new Error('Invalid code or auth state for the user.');
},
getCurrentUser: async () => {
return {
userId: '******************',
username: 'james',
};
},
};

constructor() {
Amplify.configure(awsExports);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { ForceNewPasswordComponent } from './components/force-new-password/force
import { ForceNewPasswordFormFieldsComponent } from './components/force-new-password/force-new-password-form-fields/force-new-password-form-fields.component';
import { FormFieldComponent } from './components/form-field/form-field.component';
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component';
import { SelectMfaTypeComponent } from './components/select-mfa-type/select-mfa-type.component';
import { SetupEmailComponent } from './components/setup-email/setup-email.component';
import { SetupTotpComponent } from './components/setup-totp/setup-totp.component';
import { SignInComponent } from './components/sign-in/sign-in.component';
import { SignUpComponent } from './components/sign-up/sign-up.component';
Expand Down Expand Up @@ -59,6 +61,8 @@ import { AmplifySlotDirective } from '../../utilities/amplify-slot/amplify-slot.
PhoneNumberFieldComponent,
ForgotPasswordComponent,
SelectComponent,
SelectMfaTypeComponent,
SetupEmailComponent,
SetupTotpComponent,
SignInComponent,
SignUpComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
*ngIf="hasRouteComponent()"
>
<div data-amplify-container>
<amplify-slot name="header" [context]="context"></amplify-slot>
<amplify-slot
name="header"
[context]="context"
></amplify-slot>
<div
data-amplify-router
[attr.data-amplify-router-content]="hasTabs() ? undefined : ''"
Expand Down Expand Up @@ -122,9 +125,30 @@
>
<amplify-confirm-verify-user></amplify-confirm-verify-user>
</amplify-slot>

<!-- selectMfaType content -->
<amplify-slot
name="select-mfa-type"
[context]="context"
*ngIf="route === 'selectMfaType'"
>
<amplify-select-mfa-type></amplify-select-mfa-type>
</amplify-slot>

<!-- setupEmail content -->
<amplify-slot
name="setup-email"
[context]="context"
*ngIf="route === 'setupEmail'"
>
<amplify-setup-email></amplify-setup-email>
</amplify-slot>
</div>

<amplify-slot name="footer" [context]="context"></amplify-slot>
<amplify-slot
name="footer"
[context]="context"
></amplify-slot>
</div>
</div>

Expand All @@ -135,4 +159,4 @@
*ngIf="route === 'authenticated'"
>
<ng-content></ng-content>
</amplify-slot>
</amplify-slot>
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
[describedBy]="ariaDescribedBy"
></amplify-text-field>

<div data-amplify-sign-up-errors *ngIf="hasError()" [id]="errorId">
<div
data-amplify-sign-up-errors
*ngIf="hasError()"
[id]="errorId"
>
<div
class="amplify-text amplify-text--error"
data-variation="error"
Expand All @@ -50,4 +54,4 @@
{{ translate(error) }}
</div>
</div>
</div>
</div>
Loading
Loading