Skip to content

Commit 6a043d3

Browse files
author
Niharika Arora
committed
Biometric(Single tap passkey creation & sign-in) implementation in MyVault Provider
1 parent 46c3fc3 commit 6a043d3

File tree

1 file changed

+67
-55
lines changed
  • CredentialProvider/MyVault/app/src/main/java/com/example/android/authentication/myvault/ui

1 file changed

+67
-55
lines changed

CredentialProvider/MyVault/app/src/main/java/com/example/android/authentication/myvault/ui/GetPasskeyActivity.kt

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.credentials.exceptions.GetCredentialUnknownException
3434
import androidx.credentials.provider.BiometricPromptResult
3535
import androidx.credentials.provider.CallingAppInfo
3636
import androidx.credentials.provider.PendingIntentHandler
37+
import androidx.credentials.provider.ProviderGetCredentialRequest
3738
import androidx.fragment.app.FragmentActivity
3839
import com.example.android.authentication.myvault.AppDependencies
3940
import com.example.android.authentication.myvault.R
@@ -73,10 +74,31 @@ class GetPasskeyActivity : FragmentActivity() {
7374
}
7475

7576
/**
76-
* Handle the intent for get public key credential (passkey)
77+
* Handles the intent for retrieving a public key credential (passkey).
78+
*
79+
* <p>This method processes the incoming intent to retrieve a passkey. It
80+
* extracts the necessary data from the intent, including the
81+
* {@link ProviderGetCredentialRequest} and additional request information.
82+
* It then checks for errors and proceeds to configure the passkey assertion.
83+
*
84+
* <p>The method performs the following steps:
85+
* <ol>
86+
* <li>Retrieves the request information and the {@link ProviderGetCredentialRequest}
87+
* from the intent.</li>
88+
* <li>Checks if the request information or the request itself is null. If so,
89+
* it sets up a failure response and finishes the activity.</li>
90+
* <li>Retrieves the {@link androidx.credentials.provider.BiometricPromptResult}
91+
* from the request.</li>
92+
* <li>Checks for errors in the biometric flow using {@link #isValidBiometricFlowError}.
93+
* If an error is detected, it returns early.</li>
94+
* <li>Configures the passkey assertion using {@link #configurePasskeyAssertion}.</li>
95+
* </ol>
7796
*/
7897
private fun handleGetPasskeyIntent() {
98+
// Retrieve the request information from the intent.
7999
val requestInfo = intent.getBundleExtra(getString(R.string.vault_data))
100+
101+
// Retrieve the boolean indicating if the passkey is auto selected.
80102
intent.getBooleanExtra(getString(R.string.is_auto_selected), false)
81103

82104
/*
@@ -86,31 +108,66 @@ class GetPasskeyActivity : FragmentActivity() {
86108
*/
87109
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
88110

111+
// Check if the request information or the request itself is null.
89112
if (requestInfo == null || request == null) {
113+
// If either is null, set up a failure response and finish the activity.
90114
setUpFailureResponseAndFinish(getString(R.string.unable_to_retrieve_data_from_intent))
91115
return
92116
}
93117

118+
// Retrieve the BiometricPromptResult from the request.
94119
val biometricPromptResult = request.biometricPromptResult
95120

121+
// Check if there was an error in the biometric flow.
96122
if (isValidBiometricFlowError(biometricPromptResult)) return
97123

98-
val publicKeyCredentialOption = request.credentialOptions[0]
124+
// Configure the passkey assertion.
125+
configurePasskeyAssertion(
126+
biometricPromptResult,
127+
requestInfo,
128+
request,
129+
)
130+
}
131+
132+
/**
133+
* Configures the passkey assertion process.
134+
*
135+
* <p>This method orchestrates the passkey assertion process by retrieving
136+
* necessary data from the request, validating the calling application, and
137+
* determining whether to use the biometric or default flow for assertion.
138+
*
139+
* @param biometricPromptResult The result of the biometric authentication prompt.
140+
* @param requestInfo The bundle containing additional request information.
141+
* @param request The {@link ProviderGetCredentialRequest} containing the
142+
* credential request details.
143+
*/
144+
private fun configurePasskeyAssertion(
145+
biometricPromptResult: BiometricPromptResult?,
146+
requestInfo: Bundle,
147+
request: ProviderGetCredentialRequest,
148+
) {
149+
// Retrieve the encoded credential ID from the request information.
150+
val credentialIdEncoded = requestInfo.getString(getString(R.string.cred_id))!!
151+
152+
// Retrieve the PasskeyItem from the data source using the encoded credential ID.
153+
val passkey = credentialsDataSource.getPasskey(credentialIdEncoded)!!
99154

100-
// Extract the GetPublicKeyCredentialOption from the request retrieved above.
155+
// Extract the GetPublicKeyCredentialOption from the request.
156+
val publicKeyCredentialOption = request.credentialOptions[0]
101157
val publicKeyRequest = publicKeyCredentialOption as GetPublicKeyCredentialOption
158+
159+
// Create a PublicKeyCredentialRequestOptions object from the extracted option.
102160
val publicKeyRequestOptions = PublicKeyCredentialRequestOptions(
103161
publicKeyRequest.requestJson,
104162
)
105163

106-
val credentialIdEncoded = requestInfo.getString(getString(R.string.cred_id))!!
107-
val passkey = credentialsDataSource.getPasskey(credentialIdEncoded)!!
108-
164+
// Decode the credential ID, private key, and UID from their base64 encoded forms.
109165
val credentialID = b64Decode(credentialIdEncoded)
110166
val privateKey = b64Decode(passkey.credPrivateKey)
111167
val uid = b64Decode(passkey.uid)
112-
var callingAppOriginInfo: String? = null
113168

169+
// Determine the calling application's origin and validate it.
170+
var callingAppOriginInfo: String? = null
114171
if (hasRequestContainsOrigin(request.callingAppInfo)) {
115172
callingAppOriginInfo = validatePrivilegedCallingApp(
116173
request.callingAppInfo,
@@ -123,64 +180,19 @@ class GetPasskeyActivity : FragmentActivity() {
123180
)
124181
}
125182

183+
// Get the origin and package name from the calling app info.
126184
val origin = appInfoToOrigin(request.callingAppInfo)
127185
val packageName = request.callingAppInfo.packageName
128186

187+
// Convert the decoded private key to an ECPrivateKey.
129188
val convertedPrivateKey = convertPrivateKey(privateKey)
130189

131-
// Extract the requestJson and clientDataHash from this option.
190+
// Extract the client data hash if the calling application's origin is available.
132191
var clientDataHash: ByteArray? = null
133192
if (callingAppOriginInfo != null) {
134193
clientDataHash = publicKeyRequest.clientDataHash
135194
}
136195

137-
configurePasskeyAssertion(
138-
biometricPromptResult,
139-
passkey,
140-
origin,
141-
callingAppOriginInfo,
142-
publicKeyRequestOptions,
143-
uid,
144-
packageName,
145-
clientDataHash,
146-
convertedPrivateKey,
147-
credentialID,
148-
)
149-
}
150-
151-
/**
152-
* Configures the passkey assertion based on the biometric authentication result.
153-
*
154-
* <p>This method determines whether to use the biometric flow or the default
155-
* flow for asserting a passkey. If the {@link BiometricPromptResult} indicates
156-
* successful authentication, it calls {@link #assertPasskeyWithBiometricFlow}
157-
* to proceed with the biometric flow. Otherwise, it calls
158-
* {@link #assertPasskeyWithDefaultFlow} to proceed with the default flow.
159-
*
160-
* @param biometricPromptResult The result of the biometric authentication prompt.
161-
* @param passkey The {@link PasskeyItem} containing the passkey details.
162-
* @param origin The origin of the calling application.
163-
* @param callingAppOriginInfo The origin information of the calling application, if available.
164-
* @param publicKeyRequestOptions The {@link PublicKeyCredentialRequestOptions} containing the
165-
* request details.
166-
* @param uid The unique identifier associated with the passkey.
167-
* @param packageName The package name of the calling application.
168-
* @param clientDataHash The client data hash, if available.
169-
* @param convertedPrivateKey The converted private key for the passkey.
170-
* @param credentialID The credential ID of the passkey.
171-
*/
172-
private fun configurePasskeyAssertion(
173-
biometricPromptResult: BiometricPromptResult?,
174-
passkey: PasskeyItem,
175-
origin: String,
176-
callingAppOriginInfo: String?,
177-
publicKeyRequestOptions: PublicKeyCredentialRequestOptions,
178-
uid: ByteArray,
179-
packageName: String,
180-
clientDataHash: ByteArray?,
181-
convertedPrivateKey: ECPrivateKey,
182-
credentialID: ByteArray,
183-
) {
184196
// Check if the biometric prompt result indicates successful authentication.
185197
if (biometricPromptResult?.authenticationResult != null) {
186198
// If biometric authentication was successful, use the biometric flow.

0 commit comments

Comments
 (0)