Skip to content

Commit dce8c9a

Browse files
jjarvispscanlonp
andauthored
docs(js): expand passwordless examples for multistep sign in, autosign in, and switching flows (#8138)
* add additional detail to switching auth flows page * expand autosignin examples * clarify language * fix wording * add passwordless steps to multistep sign in page * tweak language * Update src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx Co-authored-by: Parker Scanlon <[email protected]> --------- Co-authored-by: Parker Scanlon <[email protected]>
1 parent af8d6f3 commit dce8c9a

File tree

3 files changed

+153
-22
lines changed
  • src/pages/[platform]/build-a-backend/auth/connect-your-frontend

3 files changed

+153
-22
lines changed

src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP') {
8080
});
8181
}
8282

83+
if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_PASSWORD') {
84+
// collect password from user
85+
await confirmSignIn({
86+
challengeResponse: 'hunter2',
87+
});
88+
}
89+
90+
if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION') {
91+
// present nextStep.availableChallenges to user
92+
// collect user selection
93+
await confirmSignIn({
94+
challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP'
95+
});
96+
}
97+
8398
if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') {
8499
// collect custom challenge answer from user
85100
await confirmSignIn({
@@ -361,6 +376,78 @@ async function handleMfaSelection(mfaType: MfaType) {
361376

362377
```
363378

379+
## Confirm sign-in with Password
380+
381+
If the next step is `CONFIRM_SIGN_IN_WITH_PASSWORD`, the user must provide their password as the first factor authentication method. To handle this step, your implementation should prompt the user to enter their password. After the user enters the password, pass the value to the `confirmSignIn` API.
382+
383+
```ts
384+
import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth';
385+
386+
async function handleSignInResult(result: SignInOutput) {
387+
switch (result.nextStep.signInStep) {
388+
case 'CONFIRM_SIGN_IN_WITH_PASSWORD': {
389+
// Prompt user to enter their password
390+
console.log(`Please enter your password.`);
391+
break;
392+
}
393+
}
394+
}
395+
396+
async function confirmWithPassword(password: string) {
397+
const result = await confirmSignIn({ challengeResponse: password });
398+
399+
return handleSignInResult(result);
400+
}
401+
```
402+
403+
## Continue sign-in with First Factor Selection
404+
405+
If the next step is `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, the user must select a first factor method for authentication. After the user selects an option, your implementation should pass the selected method to the `confirmSignIn` API.
406+
407+
The first factor types which are currently supported by Amplify Auth are:
408+
- `SMS_OTP`
409+
- `EMAIL_OTP`
410+
- `WEB_AUTHN`
411+
- `PASSWORD`
412+
- `PASSWORD_SRP`
413+
414+
Depending on your configuration and what factors the user has previously setup, not all options may be available. Only the available options will be presented in `availableChallenges` for selection.
415+
416+
Once Amplify receives the user's selection via the `confirmSignIn` API, you can expect to handle a follow up `nextStep` corresponding with the first factor type selected:
417+
- If `SMS_OTP` is selected, `CONFIRM_SIGN_IN_WITH_SMS_CODE` will be the next step.
418+
- If `EMAIL_OTP` is selected, `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` will be the next step.
419+
- If `PASSWORD` or `PASSWORD_SRP` is selected, `CONFIRM_SIGN_IN_WITH_PASSWORD` will be the next step.
420+
- If `WEB_AUTHN` is selected, Amplify Auth will initiate the authentication ceremony on the user's device. If successful, the next step will be `DONE`.
421+
422+
423+
```ts
424+
import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth';
425+
426+
async function handleSignInResult(result: SignInOutput) {
427+
switch (result.nextStep.signInStep) {
428+
case 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION': {
429+
const { availableChallenges } = result.nextStep;
430+
// Present available first factor options to user
431+
// Prompt for selection
432+
console.log(
433+
`There are multiple first factor options available for sign in.`,
434+
);
435+
console.log(
436+
`Select a first factor type from the availableChallenges list.`,
437+
);
438+
break;
439+
}
440+
}
441+
}
442+
443+
async function handleFirstFactorSelection(firstFactorType: string) {
444+
const result = await confirmSignIn({ challengeResponse: firstFactorType });
445+
446+
return handleSignInResult(result);
447+
}
448+
449+
```
450+
364451
## Confirm sign-in with custom challenge
365452

366453
If the next step is `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the AWS Lambda trigger you configured as part of a custom sign in flow.

src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ Your application's users can also sign up using passwordless methods. To learn m
543543
```typescript
544544
// Sign up using a phone number
545545
const { nextStep: signUpNextStep } = await signUp({
546-
username: 'james',
546+
username: 'hello',
547547
options: {
548548
userAttributes: {
549549
phone_number: '+15555551234',
@@ -566,7 +566,7 @@ if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
566566

567567
// Confirm sign up with the OTP received
568568
const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
569-
username: 'james',
569+
username: 'hello',
570570
confirmationCode: '123456',
571571
});
572572

@@ -852,10 +852,10 @@ func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCa
852852
```typescript
853853
// Sign up using an email address
854854
const { nextStep: signUpNextStep } = await signUp({
855-
username: 'james',
855+
username: 'hello',
856856
options: {
857857
userAttributes: {
858-
email: 'james@example.com',
858+
email: 'hello@example.com',
859859
},
860860
},
861861
});
@@ -875,7 +875,7 @@ if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
875875

876876
// Confirm sign up with the OTP received
877877
const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
878-
username: 'james',
878+
username: 'hello',
879879
confirmationCode: '123456',
880880
});
881881

@@ -1158,19 +1158,44 @@ func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCa
11581158
<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>
11591159

11601160
```typescript
1161-
// Confirm sign up with the OTP received and auto sign in
1161+
// Call `signUp` API with `USER_AUTH` as the authentication flow type for `autoSignIn`
1162+
const { nextStep: signUpNextStep } = await signUp({
1163+
username: 'hello',
1164+
options: {
1165+
userAttributes: {
1166+
1167+
phone_number: '+15555551234',
1168+
},
1169+
autoSignIn: {
1170+
authFlowType: 'USER_AUTH',
1171+
},
1172+
},
1173+
});
1174+
1175+
if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
1176+
console.log(
1177+
`Code Delivery Medium: ${signUpNextStep.codeDeliveryDetails.deliveryMedium}`,
1178+
);
1179+
console.log(
1180+
`Code Delivery Destination: ${signUpNextStep.codeDeliveryDetails.destination}`,
1181+
);
1182+
}
1183+
1184+
// Call `confirmSignUp` API with the OTP received
11621185
const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
1163-
username: 'james',
1186+
username: 'hello',
11641187
confirmationCode: '123456',
11651188
});
11661189

11671190
if (confirmSignUpNextStep.signUpStep === 'COMPLETE_AUTO_SIGN_IN') {
1191+
// Call `autoSignIn` API to complete the flow
11681192
const { nextStep } = await autoSignIn();
11691193

11701194
if (nextStep.signInStep === 'DONE') {
11711195
console.log('Successfully signed in.');
11721196
}
11731197
}
1198+
11741199
```
11751200
</InlineFilter>
11761201
<InlineFilter filters={["android"]}>

src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -148,18 +148,9 @@ await signIn({
148148
149149
## USER_AUTH flow
150150

151-
The `USER_AUTH` sign in flow will support the following methods of first factor authentication: `WEB_AUTHN`, `EMAIL_OTP`, `SMS_OTP`, `PASSWORD`, and `PASSWORD_SRP`.
151+
The `USER_AUTH` sign in flow supports the following methods as first factors for authentication: `WEB_AUTHN`, `EMAIL_OTP`, `SMS_OTP`, `PASSWORD`, and `PASSWORD_SRP`.
152152

153-
```ts
154-
type AuthFactorType =
155-
| "WEB_AUTHN"
156-
| "EMAIL_OTP"
157-
| "SMS_OTP"
158-
| "PASSWORD"
159-
| "PASSWORD_SRP";
160-
```
161-
162-
If the desired first factor is known before the sign in flow is initiated it can be passed to the initial sign in call.
153+
If the desired first factor is known when authentication is initiated, it can be passed to the `signIn` API as the `preferredChallenge` to initiate the corresponding authentication flow.
163154

164155
```ts
165156
// PASSWORD_SRP / PASSWORD
@@ -176,19 +167,47 @@ const { nextStep } = await signIn({
176167

177168
// WEB_AUTHN / EMAIL_OTP / SMS_OTP
178169
// sign in with preferred passwordless challenge
179-
// no user input required at this step
170+
// no additional user input required at this step
180171
const { nextStep } = await signIn({
181-
username: "passwordless@mycompany.com",
172+
username: "hello@example.com",
182173
options: {
183174
authFlowType: "USER_AUTH",
184175
preferredChallenge: "WEB_AUTHN" // or "EMAIL_OTP" or "SMS_OTP"
185176
},
186177
});
187178
```
188179

189-
If the desired first factor is not known, the flow will continue to select an available first factor.
180+
If the desired first factor is not known or you would like to provide users with the available options, `preferredChallenge` can be omitted from the initial `signIn` API call.
181+
182+
This allows you to discover which authentication first factors are available for a user via the `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` step. You can then present the available options to the user and use the `confirmSignIn` API to respond with the user's selection.
183+
184+
```ts
185+
const { nextStep: signInNextStep } = await signIn({
186+
username: '+15551234567',
187+
options: {
188+
authFlowType: 'USER_AUTH',
189+
},
190+
});
191+
192+
if (
193+
signInNextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION'
194+
) {
195+
// present user with list of available challenges
196+
console.log(`Available Challenges: ${signInNextStep.availableChallenges}`);
197+
198+
// respond with user selection using `confirmSignIn` API
199+
const { nextStep: nextConfirmSignInStep } = await confirmSignIn({
200+
challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP'
201+
});
202+
}
203+
204+
```
205+
Also, note that if the `preferredChallenge` passed to the initial `signIn` API call is unavailable for the user, Amplify will also respond with the `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` next step.
206+
190207

191-
> For more information about determining a first factor, and signing in with passwordless authorization factors, please visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/)
208+
<Callout>
209+
For more information about determining a first factor, and signing in with passwordless authentication factors, please visit the [Passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/) concepts page.
210+
</Callout>
192211

193212
## USER_PASSWORD_AUTH flow
194213

0 commit comments

Comments
 (0)