diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift index 8c26cb155e..b81e60a8ae 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift @@ -16,6 +16,9 @@ import AWSClientRuntime @_spi(InternalHttpEngineProxy) import AWSPluginsCore import SmithyRetriesAPI import SmithyRetries +#if os(iOS) && canImport(UIKit) +import UIKit +#endif extension AWSCognitoAuthPlugin { @@ -38,6 +41,15 @@ extension AWSCognitoAuthPlugin { AuthPluginErrorConstants.decodeConfigurationError.recoverySuggestion) } +#if os(iOS) && canImport(UIKit) + guard UIApplication.shared.isProtectedDataAvailable else { + throw PluginError.pluginConfigurationError( + AuthPluginErrorConstants.protectedDataUnavailableError.errorDescription, + AuthPluginErrorConstants.protectedDataUnavailableError.recoverySuggestion, + AWSCognitoAuthError.protectedDataUnavailable) + } +#endif + let credentialStoreResolver = CredentialStoreState.Resolver().eraseToAnyResolver() let credentialEnvironment = credentialStoreEnvironment(authConfiguration: authConfiguration) let credentialStoreMachine = StateMachine(resolver: credentialStoreResolver, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/Errors/AWSCognitoAuthError.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/Errors/AWSCognitoAuthError.swift index 5f3553979c..c53662f85b 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/Errors/AWSCognitoAuthError.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/Errors/AWSCognitoAuthError.swift @@ -111,6 +111,9 @@ public enum AWSCognitoAuthError: Error { /// The WebAuthn configuration is missing or incomplete case webAuthnConfigurationMissing + + /// Protected data is not yet available (iOS prewarming or locked state) + case protectedDataUnavailable } extension AWSCognitoAuthError: LocalizedError { @@ -185,6 +188,8 @@ extension AWSCognitoAuthError: LocalizedError { message = "The relying party ID doesn't match." case .webAuthnConfigurationMissing: message = "The WebAuthn configuration is missing or incomplete." + case .protectedDataUnavailable: + message = "Protected data is not yet available." } return "\(String(describing: Self.self)).\(self): \(message)" } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Constants/AuthPluginErrorConstants.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Constants/AuthPluginErrorConstants.swift index fe4ad79eb9..80bce64891 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Constants/AuthPluginErrorConstants.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Constants/AuthPluginErrorConstants.swift @@ -16,6 +16,11 @@ typealias AuthPluginValidationErrorString = (field: Field, enum AuthPluginErrorConstants { + static let protectedDataUnavailableError: AuthPluginErrorString = ( + "Protected data is not yet available", + "Delay Amplify calls until `UIApplication.shared.isProtectedDataAvailable` returns true" + ) + static let decodeConfigurationError: AuthPluginErrorString = ( "Unable to decode configuration", "Make sure the plugin configuration is JSONValue") diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift index de7fec46ff..14d772025b 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift @@ -7,6 +7,10 @@ import Foundation import Amplify +#if os(iOS) && canImport(UIKit) +import UIKit +#endif + protocol AmplifyAuthTask { associatedtype Success @@ -30,6 +34,14 @@ extension AmplifyAuthTask where Self: DefaultLogger { get async throws { do { log.info("Starting execution for \(eventName)") +#if os(iOS) && canImport(UIKit) + guard await UIApplication.shared.isProtectedDataAvailable else { + throw AuthError.configuration( + AuthPluginErrorConstants.protectedDataUnavailableError.errorDescription, + AuthPluginErrorConstants.protectedDataUnavailableError.recoverySuggestion, + AWSCognitoAuthError.protectedDataUnavailable) + } +#endif let valueReturned = try await execute() log.info("Successfully completed execution for \(eventName) with result:\n\(valueReturned)") dispatch(result: .success(valueReturned))