-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(auth): add support for passwordless sign up and auto sign in (#160)
* add autoSignIn() category API definitions (#152) * add autoSignIn() category API definitions * add sign up step for auto sign in * add state machine changes for autoSignIn() and signUp() (#154) * add autoSignIn() category API definitions * add sign up step for auto sign in * add state machine changes * add events and update resolvers * update sign up events and resolvers * add updates to resolver for auto sign in * update confirm sign up flow and debug code * Address review comments --------- Co-authored-by: Harsh <[email protected]> * update auto sign state machine events and resolver (#157) * update auto sign state machine events and resolver * Address review comments * update sign up and auto sign in unit tests (#159) * update sign up and auto sign in unit tests * add auto sign in tests and refactor existing tests * Add more service error tests * Address review changes --------- Co-authored-by: Harsh <[email protected]>
- Loading branch information
1 parent
a6e760b
commit 364b966
Showing
76 changed files
with
1,940 additions
and
327 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
Amplify/Categories/Auth/Request/AuthAutoSignInRequest.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation | ||
|
||
/// Request to auto sign in | ||
public struct AuthAutoSignInRequest: AmplifyOperationRequest { | ||
|
||
/// Extra request options defined in `AuthAutoSignInRequest.Options` | ||
public var options: Options | ||
|
||
public init(options: Options) { | ||
self.options = options | ||
} | ||
} | ||
|
||
public extension AuthAutoSignInRequest { | ||
|
||
struct Options { | ||
|
||
/// Extra plugin specific options, only used in special circumstances when the existing options do not provide | ||
/// a way to utilize the underlying auth plugin functionality. See plugin documentation for expected | ||
/// key/values | ||
public let pluginOptions: Any? | ||
|
||
public init(pluginOptions: Any? = nil) { | ||
self.pluginOptions = pluginOptions | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignUp/AutoSignIn.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Amplify | ||
import Foundation | ||
import AWSCognitoIdentityProvider | ||
|
||
struct AutoSignIn: Action { | ||
|
||
var identifier: String = "AutoSignIn" | ||
let signInEventData: SignInEventData | ||
let deviceMetadata: DeviceMetadata | ||
|
||
func execute(withDispatcher dispatcher: any EventDispatcher, environment: any Environment) async { | ||
do { | ||
let userPoolEnv = try environment.userPoolEnvironment() | ||
let authEnv = try environment.authEnvironment() | ||
|
||
guard let username = signInEventData.username else { | ||
logVerbose("\(#fileID) Unable to extract username from signInEventData", environment: environment) | ||
let authError = SignInError.inputValidation(field: "Unable to extract username") | ||
let event = SignInEvent( | ||
eventType: .throwAuthError(authError) | ||
) | ||
await dispatcher.send(event) | ||
return | ||
} | ||
|
||
var authParameters = [ | ||
"USERNAME": username | ||
] | ||
|
||
let configuration = userPoolEnv.userPoolConfiguration | ||
let userPoolClientId = configuration.clientId | ||
|
||
if let clientSecret = configuration.clientSecret { | ||
let clientSecretHash = ClientSecretHelper.clientSecretHash( | ||
username: username, | ||
userPoolClientId: userPoolClientId, | ||
clientSecret: clientSecret | ||
) | ||
authParameters["SECRET_HASH"] = clientSecretHash | ||
} | ||
|
||
if case .metadata(let data) = deviceMetadata { | ||
authParameters["DEVICE_KEY"] = data.deviceKey | ||
} | ||
|
||
let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( | ||
for: username, | ||
credentialStoreClient: authEnv.credentialsClient) | ||
|
||
var userContextData: CognitoIdentityProviderClientTypes.UserContextDataType? | ||
if let encodedData = await CognitoUserPoolASF.encodedContext( | ||
username: username, | ||
asfDeviceId: asfDeviceId, | ||
asfClient: userPoolEnv.cognitoUserPoolASFFactory(), | ||
userPoolConfiguration: configuration) { | ||
userContextData = .init(encodedData: encodedData) | ||
} | ||
let analyticsMetadata = userPoolEnv | ||
.cognitoUserPoolAnalyticsHandlerFactory() | ||
.analyticsMetadata() | ||
|
||
let request = InitiateAuthInput( | ||
analyticsMetadata: analyticsMetadata, | ||
authFlow: .userAuth, | ||
authParameters: authParameters, | ||
clientId: userPoolClientId, | ||
clientMetadata: signInEventData.clientMetadata, | ||
session: signInEventData.session, | ||
userContextData: userContextData | ||
) | ||
|
||
let responseEvent = try await sendRequest( | ||
request: request, | ||
username: username, | ||
environment: userPoolEnv) | ||
logVerbose("\(#fileID) Sending event \(responseEvent)", environment: environment) | ||
await dispatcher.send(responseEvent) | ||
|
||
} catch let error as SignInError { | ||
logVerbose("\(#fileID) Raised error \(error)", environment: environment) | ||
let event = SignInEvent(eventType: .throwAuthError(error)) | ||
await dispatcher.send(event) | ||
} catch { | ||
logVerbose("\(#fileID) Caught error \(error)", environment: environment) | ||
let authError = SignInError.service(error: error) | ||
let event = SignInEvent( | ||
eventType: .throwAuthError(authError) | ||
) | ||
await dispatcher.send(event) | ||
} | ||
} | ||
|
||
private func sendRequest(request: InitiateAuthInput, | ||
username: String, | ||
environment: UserPoolEnvironment) async throws -> StateMachineEvent { | ||
|
||
let cognitoClient = try environment.cognitoUserPoolFactory() | ||
logVerbose("\(#fileID) Starting execution", environment: environment) | ||
|
||
let response = try await cognitoClient.initiateAuth(input: request) | ||
return UserPoolSignInHelper.parseResponse( | ||
response, | ||
for: username, | ||
signInMethod: signInEventData.signInMethod, | ||
presentationAnchor: signInEventData.presentationAnchor | ||
) | ||
} | ||
} | ||
|
||
extension AutoSignIn: CustomDebugDictionaryConvertible { | ||
var debugDictionary: [String: Any] { | ||
[ | ||
"identifier": identifier, | ||
"signInEventData": signInEventData.debugDictionary | ||
] | ||
} | ||
} | ||
|
||
extension AutoSignIn: CustomDebugStringConvertible { | ||
var debugDescription: String { | ||
debugDictionary.debugDescription | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignUp/ConfirmSignUp.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Amplify | ||
import Foundation | ||
import AWSCognitoIdentityProvider | ||
|
||
struct ConfirmSignUp: Action { | ||
|
||
var identifier: String = "ConfirmSignUp" | ||
let data: SignUpEventData | ||
let confirmationCode: String | ||
let forceAliasCreation: Bool? | ||
|
||
func execute(withDispatcher dispatcher: any EventDispatcher, environment: any Environment) async { | ||
do { | ||
let authEnvironment = try environment.authEnvironment() | ||
let userPoolEnvironment = authEnvironment.userPoolEnvironment | ||
let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( | ||
for: data.username, | ||
credentialStoreClient: authEnvironment.credentialsClient) | ||
let client = try userPoolEnvironment.cognitoUserPoolFactory() | ||
let input = await ConfirmSignUpInput(username: data.username, | ||
confirmationCode: confirmationCode, | ||
clientMetadata: data.clientMetadata, | ||
asfDeviceId: asfDeviceId, | ||
forceAliasCreation: forceAliasCreation, | ||
session: data.session, | ||
environment: userPoolEnvironment) | ||
let response = try await client.confirmSignUp(input: input) | ||
let dataToSend = SignUpEventData( | ||
username: data.username, | ||
clientMetadata: data.clientMetadata, | ||
validationData: data.validationData, | ||
session: response.session | ||
) | ||
logVerbose("\(#fileID) ConfirmSignUp response succcess", environment: environment) | ||
|
||
if let session = response.session { | ||
await dispatcher.send(SignUpEvent(eventType: .signedUp(dataToSend, .init(.completeAutoSignIn(session))))) | ||
} else { | ||
await dispatcher.send(SignUpEvent(eventType: .signedUp(dataToSend, .init(.done)))) | ||
} | ||
} catch let error as SignUpError { | ||
let errorEvent = SignUpEvent(eventType: .throwAuthError(error)) | ||
logVerbose("\(#fileID) Sending event \(errorEvent)", | ||
environment: environment) | ||
await dispatcher.send(errorEvent) | ||
} catch { | ||
let error = SignUpError.service(error: error) | ||
let errorEvent = SignUpEvent(eventType: .throwAuthError(error)) | ||
logVerbose("\(#fileID) Sending event \(errorEvent)", | ||
environment: environment) | ||
await dispatcher.send(errorEvent) | ||
} | ||
} | ||
} | ||
|
||
extension ConfirmSignUp: CustomDebugDictionaryConvertible { | ||
var debugDictionary: [String: Any] { | ||
[ | ||
"identifier": identifier, | ||
"signUpEventData": data.debugDictionary, | ||
"confirmationCode": confirmationCode.masked(), | ||
"forceAliasCreation": forceAliasCreation | ||
] | ||
} | ||
} | ||
|
||
extension ConfirmSignUp: CustomDebugStringConvertible { | ||
var debugDescription: String { | ||
debugDictionary.debugDescription | ||
} | ||
} |
Oops, something went wrong.