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

chore(auth): add js passwordless changes #8129

Merged
merged 16 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,10 @@ The `signIn` API response will include a `nextStep` property, which can be used
| `CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED` | The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE` | The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_SMS_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` | The sign-in must be confirmed with a EMAIL code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_SMS_CODE` | The sign-in must be confirmed with an SMS code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` | The sign-in must be confirmed with an EMAIL code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `"EMAIL"` or `"TOTP"` to `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. |
Expand Down Expand Up @@ -591,6 +593,8 @@ Following sign in, you will receive a `nextStep` in the sign-in result of one of
| `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_SMS_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` | The sign-in must be confirmed with a EMAIL code from the user. Complete the process with `confirmSignIn`. |
| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. |
jjarvisp marked this conversation as resolved.
Show resolved Hide resolved
| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `"EMAIL"` or `"TOTP"` to `confirmSignIn`. |
| `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. |
Expand Down Expand Up @@ -1113,7 +1117,18 @@ Your application's users can also sign in using passwordless methods. To learn m

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

{/* */}
To request an OTP code via SMS for authentication, the challenge is passed as the challenge response to the confirm sign in API.

Amplify will respond appropriately to Cognito and return the challenge as sign in next step: `CONFIRM_SIGN_IN_WITH_SMS_CODE`:

```ts
const { nextStep } = await confirmSignIn({
challengeResponse: "SMS_OTP"
});

// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_SMS_CODE'
handleNextSignInStep(nextStep);
```

</InlineFilter>
<InlineFilter filters={["android"]}>
Expand Down Expand Up @@ -1205,7 +1220,18 @@ func confirmSignIn() -> AnyCancellable {

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

{/* */}
To request an OTP code via email for authentication, the challenge is passed as the challenge response to the confirm sign in API.

Amplify will respond appropriately to Cognito and return the challenge as sign in next step: `CONFIRM_SIGN_IN_WITH_EMAIL_CODE`:

```ts
const { nextStep } = await confirmSignIn({
challengeResponse: "EMAIL_OTP"
});

// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE'
handleNextSignInStep(nextStep);
```

</InlineFilter>
<InlineFilter filters={["android"]}>
Expand Down Expand Up @@ -1290,3 +1316,62 @@ func confirmSignIn() -> AnyCancellable {
</BlockSwitcher>

</InlineFilter>

### WebAuthn Passkeys

{/* blurb with supplemental information about handling sign-in, events, etc. */}

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

The WebAuthn credential flow is initiated by passing the challenge name to the confirm sign in api.

```ts
const { nextStep } = await confirmSignIn({
challengeResponse: "WEB_AUTHN",
});

// nextStep.signInStep === 'DONE'
handleNextSignInStep(nextStep);
```

</InlineFilter>
<InlineFilter filters={["android"]}>

{/* */}

</InlineFilter>
<InlineFilter filters={["flutter"]}>

{/* */}

</InlineFilter>
<InlineFilter filters={["swift"]}>

{/* */}

</InlineFilter>

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

### Password or SRP

Traditional password based authentication is available from this flow as well. To initiate this flow from select challenge, either `PASSWORD` or `PASSWORD_SRP` is passed as the challenge response.

```ts
const { nextStep } = await confirmSignIn({
challengeResponse: "PASSWORD_SRP", // or "PASSWORD"
});

// in both cases
// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_PASSWORD'
handleNextSignInStep(nextStep);

const { nextStep: nextNextStep } = await confirmSignIn({
challengeResponse: "Test123#",
});

// nextNextStep.signInStep === 'DONE'
handleNextSignInStep(nextNextStep);
```

</InlineFilter>
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,40 @@ Your application's users can also sign up using passwordless methods. To learn m

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

{/* */}
```typescript
// Sign up using a phone number
const { nextStep: signUpNextStep } = await signUp({
username: 'james',
options: {
userAttributes: {
phone_number: '+15555551234',
},
},
});

if (signUpNextStep.signUpStep === 'DONE') {
console.log(`SignUp Complete`);
}

if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
console.log(
`Code Delivery Medium: ${signUpNextStep.codeDeliveryDetails.deliveryMedium}`,
);
console.log(
`Code Delivery Destination: ${signUpNextStep.codeDeliveryDetails.destination}`,
);
}

// Confirm sign up with the OTP received
const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
username: 'james',
confirmationCode: '123456',
});

if (confirmSignUpNextStep.signUpStep === 'DONE') {
console.log(`SignUp Complete`);
}
```

</InlineFilter>
<InlineFilter filters={["android"]}>
Expand Down Expand Up @@ -653,7 +686,40 @@ func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCa

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

{/* */}
```typescript
// Sign up using an email address
const { nextStep: signUpNextStep } = await signUp({
username: 'james',
options: {
userAttributes: {
email: '[email protected]',
},
},
});

if (signUpNextStep.signUpStep === 'DONE') {
console.log(`SignUp Complete`);
}

if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
console.log(
`Code Delivery Medium: ${signUpNextStep.codeDeliveryDetails.deliveryMedium}`,
);
console.log(
`Code Delivery Destination: ${signUpNextStep.codeDeliveryDetails.destination}`,
);
}

// Confirm sign up with the OTP received
const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
username: 'james',
confirmationCode: '123456',
});

if (confirmSignUpNextStep.signUpStep === 'DONE') {
console.log(`SignUp Complete`);
}
```

</InlineFilter>
<InlineFilter filters={["android"]}>
Expand Down Expand Up @@ -768,8 +834,21 @@ func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCa

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

{/* */}
```typescript
// Confirm sign up with the OTP received and auto sign in
const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
username: 'james',
confirmationCode: '123456',
});
jjarvisp marked this conversation as resolved.
Show resolved Hide resolved

if (confirmSignUpNextStep.signUpStep === 'COMPLETE_AUTO_SIGN_IN') {
const { nextStep } = await autoSignIn();

if (nextStep.signInStep === 'DONE') {
console.log('Successfully signed in.');
}
}
```
</InlineFilter>
<InlineFilter filters={["android"]}>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,28 +145,84 @@ Follow the instructions in [Custom Auth Sign In](/gen1/[platform]/build-a-backen

<InlineFilter filters={["angular", "javascript", "nextjs", "react", "react-native", "vue"]}>

For client side authentication there are three different flows:
For client side authentication there are four different flows:

1. `USER_SRP_AUTH`: The `USER_SRP_AUTH` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default.
1. `USER_AUTH`: The `USER_AUTH` flow is designed to be flexible and supports both password and passwordless sign in factors. `USER_AUTH` can do username-password and SRP authentication without the other flows being configured. This flow doesn't include CUSTOM_AUTH. This is the recommended flow.

2. `USER_PASSWORD_AUTH`: The `USER_PASSWORD_AUTH` flow will send user credentials to the backend without applying SRP encryption. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials.
2. `USER_SRP_AUTH`: The `USER_SRP_AUTH` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server.

3. `CUSTOM_WITH_SRP` & `CUSTOM_WITHOUT_SRP`: Allows for a series of challenge and response cycles that can be customized to meet different requirements.
3. `USER_PASSWORD_AUTH`: The `USER_PASSWORD_AUTH` flow will send user credentials unencrypted to the backend. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials.

4. `CUSTOM_WITH_SRP` & `CUSTOM_WITHOUT_SRP`: Allows for a series of challenge and response cycles that can be customized to meet different requirements.

The Auth flow can be customized when calling `signIn`, for example:

```ts title="src/main.ts"
await signIn({
username: "[email protected]",
username: "[email protected]",
password: "hunter2",
options: {
authFlowType: 'USER_PASSWORD_AUTH'
authFlowType: 'USER_AUTH'
}
})
```

> For more information about authentication flows, please visit [AWS Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)

## USER_AUTH flow

In order to facilitate the new passwordless sign in options, Cognito is introducing a new auth flow type known as `USER_AUTH`. This flow is designed to be flexible and supports both password and passwordless sign in factors.

### Set up auth backend

Configure supported flows in your Cognito app client. In the AWS Console, this is done by ticking the checkboxes at General settings > App clients > App client information (Edit) > App client flows. If you're using the AWS CLI or CloudFormation, update your app client by adding `USER_AUTH` to the list of "Explicit Auth Flows".

### User authentication flow

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`.

```ts
type AuthFactorType =
| "WEB_AUTHN"
| "EMAIL_OTP"
| "SMS_OTP"
| "PASSWORD"
| "PASSWORD_SRP";
```

If the desired first factor is known before the sign in flow is initiated it can be passed to the initial sign in call.

Password flows will require the password to be passed in the same step. Passwordless flows do not require user input, and the challenges will be handled in the next sign in step:

```ts
// PASSWORD_SRP / PASSWORD
// sign in with preferred challenge as password
// note password must be provided in same step
const { nextStep } = await signIn({
username: "[email protected]",
password: "hunter2",
options: {
authFlowType: "USER_AUTH",
preferredChallenge: "PASSWORD_SRP" // or "PASSWORD"
},
});

// WEB_AUTHN / EMAIL_OTP / SMS_OTP
// sign in with preferred passwordless challenge
// no user input required at this step
const { nextStep } = await signIn({
username: "[email protected]",
options: {
authFlowType: "USER_AUTH",
preferredChallenge: "WEB_AUTHN" // or "EMAIL_OTP" or "SMS_OTP"
},
});
```

If the desired first factor is not known, the flow will continue to select an available first factor.

> 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/)

## USER_PASSWORD_AUTH flow

A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito
Expand Down
Loading