1515
1616package com.amplifyframework.ui.authenticator.util
1717
18+ import android.app.Activity
19+ import aws.sdk.kotlin.services.cognitoidentityprovider.getUserAuthFactors
20+ import aws.sdk.kotlin.services.cognitoidentityprovider.model.AuthFactorType as KotlinAuthFactorType
1821import com.amplifyframework.auth.AWSCognitoAuthMetadataType
1922import com.amplifyframework.auth.AuthChannelEventName
2023import com.amplifyframework.auth.AuthCodeDeliveryDetails
2124import com.amplifyframework.auth.AuthException
25+ import com.amplifyframework.auth.AuthFactorType
2226import com.amplifyframework.auth.AuthSession
2327import com.amplifyframework.auth.AuthUser
2428import com.amplifyframework.auth.AuthUserAttribute
2529import com.amplifyframework.auth.AuthUserAttributeKey
2630import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin
31+ import com.amplifyframework.auth.cognito.AWSCognitoAuthSession
2732import com.amplifyframework.auth.cognito.PasswordProtectionSettings
2833import com.amplifyframework.auth.cognito.UsernameAttribute
2934import com.amplifyframework.auth.cognito.VerificationMechanism as AmplifyVerificationMechanism
35+ import com.amplifyframework.auth.cognito.exceptions.configuration.InvalidUserPoolConfigurationException
36+ import com.amplifyframework.auth.exceptions.UnknownException
3037import com.amplifyframework.auth.options.AuthConfirmSignInOptions
3138import com.amplifyframework.auth.options.AuthSignInOptions
3239import com.amplifyframework.auth.options.AuthSignUpOptions
3340import com.amplifyframework.auth.result.AuthResetPasswordResult
3441import com.amplifyframework.auth.result.AuthSignInResult
3542import com.amplifyframework.auth.result.AuthSignOutResult
3643import com.amplifyframework.auth.result.AuthSignUpResult
44+ import com.amplifyframework.auth.result.AuthWebAuthnCredential
3745import com.amplifyframework.core.Amplify
3846import com.amplifyframework.hub.HubChannel
3947import com.amplifyframework.hub.HubEvent
@@ -81,6 +89,10 @@ internal interface AuthProvider {
8189
8290 suspend fun fetchAuthSession (): AmplifyResult <AuthSession >
8391
92+ suspend fun createPasskey (activity : Activity ): AmplifyResult <Unit >
93+
94+ suspend fun getPasskeys (): AmplifyResult <List <AuthWebAuthnCredential >>
95+
8496 suspend fun fetchUserAttributes (): AmplifyResult <List <AuthUserAttribute >>
8597
8698 suspend fun confirmUserAttribute (key : AuthUserAttributeKey , confirmationCode : String ): AmplifyResult <Unit >
@@ -89,6 +101,8 @@ internal interface AuthProvider {
89101
90102 suspend fun getCurrentUser (): AmplifyResult <AuthUser >
91103
104+ suspend fun getAvailableAuthFactors (): AmplifyResult <List <AuthFactorType >>
105+
92106 fun authStatusEvents (): Flow <HubEvent <* >>
93107
94108 suspend fun getConfiguration (): AuthConfigurationResult
@@ -197,6 +211,21 @@ internal class RealAuthProvider : AuthProvider {
197211 )
198212 }
199213
214+ override suspend fun createPasskey (activity : Activity ) = suspendCoroutine { continuation ->
215+ Amplify .Auth .associateWebAuthnCredential(
216+ activity,
217+ { continuation.resume(AmplifyResult .Success (Unit )) },
218+ { continuation.resume(AmplifyResult .Error (it)) }
219+ )
220+ }
221+
222+ override suspend fun getPasskeys (): AmplifyResult <List <AuthWebAuthnCredential >> = suspendCoroutine { continuation ->
223+ Amplify .Auth .listWebAuthnCredentials(
224+ { continuation.resume(AmplifyResult .Success (it.credentials)) },
225+ { continuation.resume(AmplifyResult .Error (it)) }
226+ )
227+ }
228+
200229 override suspend fun fetchUserAttributes () = suspendCoroutine { continuation ->
201230 Amplify .Auth .fetchUserAttributes(
202231 { continuation.resume(AmplifyResult .Success (it)) },
@@ -230,6 +259,42 @@ internal class RealAuthProvider : AuthProvider {
230259 )
231260 }
232261
262+ override suspend fun getAvailableAuthFactors (): AmplifyResult <List <AuthFactorType >> {
263+ // Get the identity provider client from Amplify
264+ val client = getCognitoPlugin()?.escapeHatch?.cognitoIdentityProviderClient ? : return AmplifyResult .Error (
265+ InvalidUserPoolConfigurationException ()
266+ )
267+
268+ // Get the user's access token
269+ val token = when (val authSession = fetchAuthSession()) {
270+ is AmplifyResult .Error -> return authSession
271+ is AmplifyResult .Success -> {
272+ val cognitoSession = authSession.data as AWSCognitoAuthSession
273+ cognitoSession.accessToken
274+ }
275+ }
276+
277+ // Fetch the list of auth factors
278+ val response = try {
279+ client.getUserAuthFactors { accessToken = token }
280+ } catch (e: Exception ) {
281+ return AmplifyResult .Error (UnknownException (" Could not fetch auth factors" , e))
282+ }
283+
284+ // Map the factors to Amplify types
285+ val factors = response.configuredUserAuthFactors?.mapNotNull { factor ->
286+ when (factor) {
287+ KotlinAuthFactorType .EmailOtp -> AuthFactorType .EMAIL_OTP
288+ KotlinAuthFactorType .Password -> AuthFactorType .PASSWORD
289+ KotlinAuthFactorType .SmsOtp -> AuthFactorType .SMS_OTP
290+ KotlinAuthFactorType .WebAuthn -> AuthFactorType .WEB_AUTHN
291+ else -> null
292+ }
293+ } ? : emptyList()
294+
295+ return AmplifyResult .Success (factors)
296+ }
297+
233298 override fun authStatusEvents (): Flow <HubEvent <* >> = callbackFlow {
234299 val filter = HubEventFilter {
235300 it.name == AuthChannelEventName .SIGNED_OUT .name || it.name == AuthChannelEventName .SIGNED_IN .name
0 commit comments