Skip to content

Commit bfcbf8d

Browse files
authored
fix(auth): Fix passkey usage on Android < 13 devices (#3039)
1 parent 09e5693 commit bfcbf8d

File tree

5 files changed

+42
-22
lines changed

5 files changed

+42
-22
lines changed

aws-auth-cognito/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ dependencies {
4141
implementation(libs.androidx.security)
4242
implementation(libs.androidx.browser)
4343
implementation(libs.androidx.credentials)
44+
implementation(libs.androidx.credentials.play.services)
4445

4546
implementation(libs.aws.http)
4647
implementation(libs.aws.cognitoidentity)

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/webauthn/WebAuthnNotSupportedException.kt

+12-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,15 @@ package com.amplifyframework.auth.cognito.exceptions.webauthn
1919
* Exception that is thrown because WebAuthn is not supported on the device. This indicates that either the device
2020
* did not ship with WebAuthn support, or that your application is missing a required dependency or service.
2121
*/
22-
class WebAuthnNotSupportedException internal constructor(cause: Throwable?) :
23-
WebAuthnFailedException(
24-
message = "WebAuthn is not supported on this device",
25-
recoverySuggestion = TODO_RECOVERY_SUGGESTION,
26-
cause = cause
27-
)
22+
class WebAuthnNotSupportedException internal constructor(
23+
message: String,
24+
cause: Throwable? = null
25+
) : WebAuthnFailedException(
26+
message = message,
27+
recoverySuggestion = TODO_RECOVERY_SUGGESTION,
28+
cause = cause
29+
) {
30+
internal constructor(
31+
cause: Throwable?
32+
) : this(message = "WebAuthn is not supported on this device", cause = cause)
33+
}

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/WebAuthnHelper.kt

+21-16
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package com.amplifyframework.auth.cognito.helpers
1717

1818
import android.app.Activity
1919
import android.content.Context
20+
import android.os.Build
2021
import androidx.credentials.CreateCredentialResponse
2122
import androidx.credentials.CreatePublicKeyCredentialRequest
2223
import androidx.credentials.CreatePublicKeyCredentialResponse
@@ -75,22 +76,26 @@ internal class WebAuthnHelper(
7576
}
7677

7778
suspend fun createCredential(requestJson: String, callingActivity: Activity): String {
78-
try {
79-
// Create the request for CredentialManager
80-
val request = CreatePublicKeyCredentialRequest(requestJson)
81-
82-
// Create the credential
83-
logger.verbose("Prompting user to create a PassKey")
84-
val result: CreateCredentialResponse = credentialManager.createCredential(callingActivity, request)
85-
86-
// Extract the Public Key registration response. This is what we send to Cognito.
87-
val publicKeyResult = result as? CreatePublicKeyCredentialResponse ?: throw WebAuthnFailedException(
88-
"Android created wrong credential type",
89-
AmplifyException.REPORT_BUG_TO_AWS_SUGGESTION
90-
)
91-
return publicKeyResult.registrationResponseJson
92-
} catch (e: CreateCredentialException) {
93-
throw e.toAuthException()
79+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
80+
try {
81+
// Create the request for CredentialManager
82+
val request = CreatePublicKeyCredentialRequest(requestJson)
83+
84+
// Create the credential
85+
logger.verbose("Prompting user to create a PassKey")
86+
val result: CreateCredentialResponse = credentialManager.createCredential(callingActivity, request)
87+
88+
// Extract the Public Key registration response. This is what we send to Cognito.
89+
val publicKeyResult = result as? CreatePublicKeyCredentialResponse ?: throw WebAuthnFailedException(
90+
"Android created wrong credential type",
91+
AmplifyException.REPORT_BUG_TO_AWS_SUGGESTION
92+
)
93+
return publicKeyResult.registrationResponseJson
94+
} catch (e: CreateCredentialException) {
95+
throw e.toAuthException()
96+
}
97+
} else {
98+
throw WebAuthnNotSupportedException("Passkeys are only supported on API 28 and above")
9499
}
95100
}
96101

build.gradle.kts

+5
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ fun Project.configureAndroid() {
191191

192192
dependencies {
193193
add("coreLibraryDesugaring", libs.android.desugartools)
194+
constraints {
195+
add("implementation", libs.androidx.annotation.experimental) {
196+
because("Fixes a lint bug with RequiresOptIn")
197+
}
198+
}
194199
}
195200
}
196201
}

gradle/libs.versions.toml

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
agp = "8.4.0"
33
androidx-activity = "1.2.0"
44
androidx-annotation = "1.9.1"
5+
androidx-annotation-experimental = "1.4.1"
56
androidx-appcompat = "1.2.0"
67
androidx-browser = "1.4.0"
78
androidx-concurrent = "1.1.0"
@@ -57,11 +58,13 @@ turbine = "1.1.0"
5758
android-desugartools = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar" }
5859
androidx-activity = { module = "androidx.activity:activity", version.ref = "androidx-activity" }
5960
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
61+
androidx-annotation-experimental = { module = "androidx.annotation:annotation-experimental", version.ref = "androidx-annotation-experimental" }
6062
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref="androidx-appcompat" }
6163
androidx-browser = { module = "androidx.browser:browser", version.ref = "androidx-browser" }
6264
androidx-core = { module = "androidx.core:core", version.ref = "androidx-core" }
6365
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
6466
androidx-credentials = { module = "androidx.credentials:credentials", version.ref="androidx-credentials" }
67+
androidx-credentials-play-services = { module = "androidx.credentials:credentials-play-services-auth", version.ref="androidx-credentials" }
6568
androidx-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junit-ktx" }
6669
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "androidx-lifecycle" }
6770
androidx-nav-fragment = { module = "androidx.navigation:navigation-fragment", version.ref = "navigation" }

0 commit comments

Comments
 (0)