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(Auth): Adding TOTP support in Amplify Auth category #3040

Merged
merged 3 commits into from
Jul 3, 2023
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
14 changes: 14 additions & 0 deletions Amplify/Categories/Auth/AuthCategory+ClientBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,18 @@ extension AuthCategory: AuthCategoryBehavior {
) async throws {
try await plugin.confirmResetPassword(for: username, with: newPassword, confirmationCode: confirmationCode, options: options)
}

public func setUpTOTP(
options: SetUpTOTPRequest.Options? = nil
) async throws -> TOTPSetupDetails {
try await plugin.setUpTOTP(options: options)
}

public func verifyTOTPSetup(
code: String,
options: VerifyTOTPSetupRequest.Options? = nil
) async throws {
try await plugin.verifyTOTPSetup(code: code, options: options)
}

}
25 changes: 25 additions & 0 deletions Amplify/Categories/Auth/AuthCategoryBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,29 @@ public protocol AuthCategoryBehavior: AuthCategoryUserBehavior, AuthCategoryDevi
/// - options: Parameters specific to plugin behavior
func confirmResetPassword(for username: String, with newPassword: String, confirmationCode: String, options: AuthConfirmResetPasswordRequest.Options?) async throws

/// Initiates TOTP Setup
harsh62 marked this conversation as resolved.
Show resolved Hide resolved
///
/// Invoke this operation to setup TOTP for the user while signed in.
/// Calling this method will initiate TOTP setup process and returns a shared secret that can be used to generate QR code.
/// The setup details also contains a URI generator helper that can be used to retireve a TOTP Setup URI.
///
/// - Parameters:
/// - options: Parameters specific to plugin behavior
func setUpTOTP(
options: SetUpTOTPRequest.Options?
) async throws -> TOTPSetupDetails

/// Verifies TOTP Setup
harsh62 marked this conversation as resolved.
Show resolved Hide resolved
///
/// Invoke this operation to verify TOTP setup for the user while signed in.
/// Calling this method with the verification code from the associated Authenticator app will complete the TOTP setup process.
///
/// - Parameters:
/// - code: verification code from the associated Authenticator app
/// - options: Parameters specific to plugin behavior
func verifyTOTPSetup(
code: String,
options: VerifyTOTPSetupRequest.Options?
) async throws

}
16 changes: 16 additions & 0 deletions Amplify/Categories/Auth/Models/AuthSignInStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
// SPDX-License-Identifier: Apache-2.0
//

/// Set of allowed MFA types that would be used for continuing sign in during MFA selection step
public typealias AllowedMFATypes = Set<MFAType>

/// Auth SignIn flow steps
///
///
Expand All @@ -23,6 +26,19 @@ public enum AuthSignInStep {
///
case confirmSignInWithNewPassword(AdditionalInfo?)

/// Auth step is TOTP multi factor authentication.
///
/// Confirmation code for the MFA will be retrieved from the associated Authenticator app
case confirmSignInWithTOTPCode

/// Auth step is for continuing sign in by setting up TOTP multi factor authentication.
///
case continueSignInWithTOTPSetup(TOTPSetupDetails)

/// Auth step is for continuing sign in by selecting multi factor authentication type
///
case continueSignInWithMFASelection(AllowedMFATypes)

/// Auth step required the user to change their password.
///
case resetPassword(AdditionalInfo?)
Expand Down
15 changes: 15 additions & 0 deletions Amplify/Categories/Auth/Models/MFAType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

public enum MFAType: String {

/// Short Messaging Service linked with a phone number
case sms

/// Time-based One Time Password linked with an authenticator app
case totp
}
42 changes: 42 additions & 0 deletions Amplify/Categories/Auth/Models/TOTPSetupDetails.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

public struct TOTPSetupDetails {

/// Secret code returned by the service to help setting up TOTP
public let sharedSecret: String

/// username that will be used to construct the URI
public let username: String

public init(sharedSecret: String, username: String) {
self.sharedSecret = sharedSecret
self.username = username
}
/// Returns a TOTP setup URI that can help the customers avoid barcode scanning and use native password manager to handle TOTP association
/// Example: On iOS and MacOS, URI will redirect to associated Password Manager for the platform
///
/// throws AuthError.validation if a `URL` cannot be formed with the supplied parameters
/// (for example, if the parameter string contains characters that are illegal in a URL, or is an empty string).
public func getSetupURI(
appName: String,
accountName: String? = nil) throws -> URL {
guard let URL = URL(
string: "otpauth://totp/\(appName):\(accountName ?? username)?secret=\(sharedSecret)&issuer=\(appName)") else {

throw AuthError.validation(
"appName or accountName",
"Invalid Parameters. Cannot form URL from the supplied appName or accountName",
"Please make sure that the supplied parameters don't contain any characters that are illegal in a URL or is an empty String",
nil)
}
return URL
}

}
34 changes: 34 additions & 0 deletions Amplify/Categories/Auth/Request/SetUpTOTPRequest.swift
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 set up TOTP
public struct SetUpTOTPRequest: AmplifyOperationRequest {

/// Extra request options defined in `SetUpTOTPRequest.Options`
public var options: Options

public init(options: Options) {
self.options = options
}
}

public extension SetUpTOTPRequest {

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
}
}
}
40 changes: 40 additions & 0 deletions Amplify/Categories/Auth/Request/VerifyTOTPSetupRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

/// Request to verify TOTP setup
public struct VerifyTOTPSetupRequest: AmplifyOperationRequest {

/// Code from the associated Authenticator app that will be used for verification
public var code: String

/// Extra request options defined in `VerifyTOTPSetupRequest.Options`
public var options: Options

public init(
code: String,
options: Options) {
self.code = code
self.options = options
}
}

public extension VerifyTOTPSetupRequest {

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
}
}
}