-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(Auth): Adding documentation for federation and switching auth flow type #4768
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
Changes from all commits
c91ebd4
a7dcb87
a40ffdb
d579538
58e86e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -288,6 +288,11 @@ const directory = { | |
route: '/lib/auth/signin', | ||
filters: ['android', 'flutter', 'ios'] | ||
}, | ||
{ | ||
title: 'Switching authentication flows', | ||
route: '/lib/auth/switch-auth', | ||
filters: ['ios'] | ||
}, | ||
{ | ||
title: 'Sign in with custom flow', | ||
route: '/lib/auth/signin_with_custom_flow', | ||
|
@@ -363,6 +368,11 @@ const directory = { | |
route: '/lib/auth/escapehatch', | ||
filters: ['android', 'ios'] | ||
}, | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing here for advanced workflow? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I use the existing directory entry, it messes up the order.. For example:
|
||
title: 'Advanced workflows', | ||
route: '/lib/auth/advanced', | ||
filters: ['ios'] | ||
}, | ||
{ | ||
title: 'Under the hood', | ||
route: '/lib/auth/overview', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
## Subscribing Events | ||
|
||
You can take specific actions when users sign-in or sign-out by subscribing authentication events in your app. Please see our [Hub Module Developer Guide](/lib/utilities/hub) for more information. | ||
|
||
## Identity Pool Federation | ||
|
||
Imagine that you are creating a mobile app that accesses AWS resources, such as a game that runs on a mobile device and stores player and score information using Amazon S3 and DynamoDB. | ||
|
||
When you write such an app, you make requests to AWS services that must be signed with an AWS access key. However, we strongly recommend that you do not embed or distribute long-term AWS credentials with apps that a user downloads to a device, even in an encrypted store. Instead, build your app so that it requests temporary AWS security credentials dynamically when needed using web identity federation. The supplied temporary credentials map to an AWS role that has only the permissions needed to perform the tasks required by the mobile app. | ||
|
||
With web identity federation, you don't need to create custom sign-in code or manage your own user identities. Instead, users of your app can sign in using a well-known external identity provider (IdP), such as Login with Amazon, Facebook, Google, or any other OpenID Connect (OIDC)-compatible IdP. They can receive an authentication token, and then exchange that token for temporary security credentials in AWS that map to an IAM role with permissions to use the resources in your AWS account. Using an IdP helps you keep your AWS account secure, because you don't have to embed and distribute long-term security credentials with your application. | ||
|
||
You can use `federateToIdentityPool` to get AWS credentials directly from Cognito Federated Identities and not use User Pool federation. If you have logged in with `Auth.signIn` you **can not** call `federateToIdentityPool` as Amplify will perform this federation automatically for you in the background. In general, you should only call `Auth.federatedSignIn()` when using OAuth flows. | ||
|
||
You can use the escape hatch API `federateToIdentityPool` with a valid token from other social providers. | ||
|
||
```swift | ||
func federateToIdentityPools() async throws { | ||
guard let authCognitoPlugin = try Amplify.Auth.getPlugin( | ||
for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else { | ||
fatalError("Unable to get the Auth plugin") | ||
} | ||
do { | ||
let result = try await authCognitoPlugin.federateToIdentityPool( | ||
withProviderToken: "YOUR_TOKEN", for: .facebook) | ||
print("Federation successful with result: \(result)") | ||
} catch { | ||
print("Failed to federate to identity pools with error: \(error)") | ||
} | ||
} | ||
``` | ||
|
||
<Callout> | ||
Note that when federated, API's such as Auth.getCurrentUser() will throw an error as the user is not authenticated with User Pools. | ||
</Callout> | ||
|
||
### Retrieve Session | ||
|
||
After federated login, you can retrieve session using the `Auth.fetchAuthSession` API. | ||
|
||
### Token Refresh | ||
|
||
<Callout> | ||
NOTE: Automatic authentication token refresh is NOT supported when federated. | ||
</Callout> | ||
|
||
By default, Amplify will **NOT** automatically refresh the tokens from the federated providers. You will need to handle the token refresh logic and provide the new token to the `federateToIdentityPool` API. | ||
|
||
### Clear Session | ||
|
||
You can clear the federated session using the `clearFederationToIdentityPool` API. | ||
|
||
```swift | ||
func clearFederationToIdentityPools() async throws { | ||
guard let authCognitoPlugin = try Amplify.Auth.getPlugin( | ||
for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else { | ||
fatalError("Unable to get the Auth plugin") | ||
} | ||
do { | ||
try await authCognitoPlugin.clearFederationToIdentityPool() | ||
print("Federation cleared successful") | ||
} catch { | ||
print("Clear federation failed with error: \(error)") | ||
} | ||
} | ||
``` | ||
|
||
<Callout> | ||
clearFederationToIdentityPool will only clear the session from local cache, developer need to handle signing out from the federated provider. | ||
</Callout> | ||
|
||
### Provide Custom Identity Id | ||
|
||
You can provide a custom identity id to the `federateToIdentityPool` API. This is useful when you want to use the same identity id across multiple devices. | ||
|
||
```swift | ||
func federateToIdentityPoolsUsingCustomIdentityId() async throws { | ||
guard let authCognitoPlugin = try Amplify.Auth.getPlugin( | ||
for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else { | ||
fatalError("Unable to get the Auth plugin") | ||
} | ||
do { | ||
let identityId = "YOUR_CUSTOM_IDENTITY_ID" | ||
let result = try await authCognitoPlugin.federateToIdentityPool( | ||
withProviderToken: "YOUR_TOKEN", | ||
for: .facebook, | ||
options: .init(developerProvidedIdentityID: identityId)) | ||
print("Federation successful with result: \(result)") | ||
} catch { | ||
print("Failed to federate to identity pools with error: \(error)") | ||
} | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
`AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplifyconfiguration.json` file or pass the `authFlowType` as a runtime parameter to the `signIn` api call. | ||
|
||
For client side authentication there are four different flows that can be configured during runtime: | ||
|
||
1. `userSRP`: The `userSRP` flow uses the <a href="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol" target="_blank">SRP protocol (Secure Remote Password)</a> where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default. | ||
|
||
2. `userPassword`: The `userPassword` flow will send user credentials unencrypted to the back-end. 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. | ||
|
||
3. `customWithSRP`: The `customWithSRP` flow is used to start with SRP authentication and then switch to custom authentication. This is useful if you want to use SRP for the initial authentication and then use custom authentication for subsequent authentication attempts. | ||
|
||
4. `customWithoutSRP`: The `customWithoutSRP` flow is used to start authentication flow **WITHOUT** SRP and then use a series of challenge and response cycles that can be customized to meet different requirements. | ||
|
||
`Auth` can be configured to use the different flows at runtime by calling `signIn` with `AuthSignInOptions`'s `authFlowType` as `AuthFlowType.userPassword`, `AuthFlowType.customAuthWithoutSrp` or `AuthFlowType.customAuthWithSrp`. If you do not specify the `AuthFlowType` in `AuthSignInOptions`, the default flow (`AuthFlowType.userSRP`) will be used. | ||
|
||
```swift | ||
public enum AuthFlowType: String { | ||
|
||
/// Authentication flow for the Secure Remote Password (SRP) protocol | ||
case userSRP | ||
|
||
/// Authentication flow for custom flow which are backed by lambda triggers. | ||
/// Note that `custom`will always begin with a SRP flow. | ||
@available(*, deprecated, message: "Use of custom is deprecated, use customWithSrp or customWithoutSrp instead") | ||
case custom | ||
|
||
/// Authentication flow which start with SRP and then move to custom auth flow | ||
case customWithSRP | ||
|
||
/// Authentication flow which starts without SRP and directly moves to custom auth flow | ||
case customWithoutSRP | ||
|
||
/// Non-SRP authentication flow; user name and password are passed directly. | ||
/// If a user migration Lambda trigger is set, this flow will invoke the user migration | ||
/// Lambda if it doesn't find the user name in the user pool. | ||
case userPassword | ||
} | ||
``` | ||
|
||
<Callout> | ||
|
||
Runtime configuration will take precedence and will override any auth flow type configuration present in amplifyconfiguration.json | ||
|
||
</Callout> | ||
|
||
> 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_PASSWORD_AUTH flow | ||
|
||
A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito | ||
harsh62 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
A user migration Lambda trigger helps migrate users from a legacy user management system into your user pool. If you choose the USER_PASSWORD_AUTH authentication flow, users don't have to reset their passwords during user migration. This flow sends your users' passwords to the service over an encrypted SSL connection during authentication. | ||
|
||
When you have migrated all your users, switch flows to the more secure SRP flow. The SRP flow doesn't send any passwords over the network. | ||
|
||
```swift | ||
func signIn(username: String, password: String) async throws { | ||
|
||
let option = AWSAuthSignInOptions(authFlowType: .userPassword) | ||
do { | ||
let result = try await Amplify.Auth.signIn( | ||
username: username, | ||
password: password, | ||
options: AuthSignInRequest.Options(pluginOptions: option)) | ||
print("Sign in succeeded with result: \(result)") | ||
} catch { | ||
print("Failed to sign in with error: \(error)") | ||
} | ||
} | ||
``` | ||
|
||
### Setup auth backend | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should add a section on how this works when we have auth type in amplifyconfiguration.json There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can do that as a follow up |
||
|
||
In order to use the authentication flow `USER_PASSWORD_AUTH`, your Cognito app client has to be configured to allow it. In the AWS Console, this is done by ticking the checkbox at General settings > App clients > Show Details (for the affected client) > Enable username-password (non-SRP) flow. If you're using the AWS CLI or CloudFormation, update your app client by adding `USER_PASSWORD_AUTH` to the list of "Explicit Auth Flows". | ||
|
||
### Migrate users with Amazon Cognito | ||
|
||
Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password. | ||
|
||
In short, the Lambda function will validate the user credentials against your existing user directory and return a response object containing the user attributes and status on success. An error message will be returned if an error occurs. There's a documentation [here](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html) on how to set up this migration flow and more detailed instructions [here](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html#cognito-user-pools-lambda-trigger-syntax-user-migration) on how the lambda should handle request and response objects. | ||
|
||
## CUSTOM_AUTH flow | ||
|
||
Amazon Cognito User Pools supports customizing the authentication flow to enable custom challenge types, in addition to a password in order to verify the identity of users. The custom authentication flow is a series of challenge and response cycles that can be customized to meet different requirements. These challenge types may include CAPTCHAs or dynamic challenge questions. | ||
|
||
To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito. | ||
|
||
The flow is initiated by calling `signIn` with `AuthSignInOptions` configured with `AuthFlowType.customAuthWithSrp` OR `AuthFlowType.customAuthWithoutSrp`. | ||
|
||
Follow the instructions in [Custom Auth Sign In](/lib/auth/signin_with_custom_flow) to learn about how to integrate custom authentication flow in your application with the Auth APIs. | ||
|
||
<Callout> | ||
|
||
For more information about working with Lambda Triggers for custom authentication challenges, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html). | ||
|
||
</Callout> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you please use the existing Switching authentication flows directory entry? Rather than creating another one just for iOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar is the case here.. If I use the existing one, Switch Auth would be the first option whereas we want it to come after sign in..