Skip to content

fix(auth): Update exception handling for devices that don't support passkeys #3044

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

Merged
merged 2 commits into from
May 6, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@ package com.amplifyframework.auth.cognito.exceptions.webauthn

/**
* Exception that is thrown because WebAuthn is not supported on the device. This indicates that either the device
* did not ship with WebAuthn support, or that your application is missing a required dependency or service.
* is too old or it did not ship with WebAuthn support, or that your application is missing a required dependency
* or service.
*/
class WebAuthnNotSupportedException internal constructor(
message: String,
cause: Throwable? = null
) : WebAuthnFailedException(
message = message,
recoverySuggestion = TODO_RECOVERY_SUGGESTION,
recoverySuggestion = if (cause != null) {
RECOVERY_SUGGESTION_WITH_THROWABLE
} else {
TODO_RECOVERY_SUGGESTION
},
cause = cause
) {
internal constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import androidx.credentials.exceptions.GetCredentialUnsupportedException
import androidx.credentials.exceptions.domerrors.DataError
import androidx.credentials.exceptions.domerrors.InvalidStateError
import androidx.credentials.exceptions.domerrors.NotAllowedError
import androidx.credentials.exceptions.domerrors.NotSupportedError
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialException
import androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialDomException
Expand Down Expand Up @@ -123,6 +124,7 @@ internal class WebAuthnHelper(
is NotAllowedError -> userCancelledException()
is InvalidStateError -> alreadyExists()
is DataError -> rpMismatch()
is NotSupportedError -> notSupported()
else -> unknownException()
}
}
Expand All @@ -137,6 +139,7 @@ internal class WebAuthnHelper(
when (this.domError) {
is NotAllowedError -> userCancelledException()
is DataError -> rpMismatch()
is NotSupportedError -> notSupported()
else -> unknownException()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ package com.amplifyframework.auth.cognito.helpers

import android.app.Activity
import android.content.Context
import androidx.credentials.CreatePublicKeyCredentialRequest
import androidx.credentials.CreatePublicKeyCredentialResponse
import androidx.credentials.CredentialManager
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetCredentialResponse
import androidx.credentials.PublicKeyCredential
import androidx.credentials.exceptions.domerrors.NotSupportedError
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
import androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialDomException
import com.amplifyframework.auth.cognito.exceptions.webauthn.WebAuthnNotSupportedException
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.assertions.throwables.shouldThrowWithMessage
import io.kotest.matchers.shouldBe
import io.mockk.coEvery
import io.mockk.coVerify
Expand All @@ -31,6 +38,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

@RunWith(RobolectricTestRunner::class)
class WebAuthnHelperTest {
Expand Down Expand Up @@ -72,9 +80,37 @@ class WebAuthnHelperTest {
}
}

@Test
fun `throws WebAuthnNotSupportedException for NotSupported error for get`() = runTest {
coEvery { credentialManager.getCredential(any(), any<GetCredentialRequest>()) } throws
GetPublicKeyCredentialDomException(NotSupportedError())

shouldThrow<WebAuthnNotSupportedException> {
helper.getCredential(requestJson, mockk())
}
}

@Test
fun `creates credential`() = runTest {
val result = helper.createCredential(requestJson, mockk())
result shouldBe responseJson
}

@Test
fun `throws WebAuthnNotSupportedException for NotSupported error for create`() = runTest {
coEvery { credentialManager.createCredential(any(), any<CreatePublicKeyCredentialRequest>()) } throws
CreatePublicKeyCredentialDomException(NotSupportedError())

shouldThrow<WebAuthnNotSupportedException> {
helper.createCredential(requestJson, mockk())
}
}

@Config(sdk = [27])
@Test
fun `throws WebAuthnNotSupportedException for devices below API 28`() = runTest {
shouldThrowWithMessage<WebAuthnNotSupportedException>("Passkeys are only supported on API 28 and above") {
helper.createCredential(requestJson, mockk())
}
}
}
Loading