From 31929e36a041d7dcf5527fd4bf292c885056241c Mon Sep 17 00:00:00 2001 From: Michael Feher Date: Tue, 3 Sep 2024 08:14:13 -0400 Subject: [PATCH] docs: provider service authentication --- .../provider-service/authentication.mdx | 114 +++++++++++++++++- .../android/provider-service/introduction.mdx | 4 +- 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/docs/src/content/docs/clients/android/provider-service/authentication.mdx b/docs/src/content/docs/clients/android/provider-service/authentication.mdx index 377d30b..a5a5a02 100644 --- a/docs/src/content/docs/clients/android/provider-service/authentication.mdx +++ b/docs/src/content/docs/clients/android/provider-service/authentication.mdx @@ -2,4 +2,116 @@ title: "Android 14: Authentication Service" --- -# Provider Service +import {Steps, TabItem, Tabs} from '@astrojs/starlight/components'; +import CodeUri from "@/components/CodeUri.astro"; + +To handle sign in requests in your credential provider service, complete the steps shown in the following sections. + +## Query + +User sign-in is handled with the following steps: + + +1. When a device tries to sign in a user, it prepares a [GetCredentialRequest](https://developer.android.com/reference/androidx/credentials/GetCredentialRequest) instance. +2. The Android framework propagates this request to all applicable credential providers by binding to these services. +3. The provider service then receives a `BeginGetCredentialRequest` that contains a list of `BeginGetCredentialOption`, + each of which contains parameters that can be used to retrieve matching credentials. + + +To handle this request in your credential provider service, +you can override the `onBeginGetCredentialRequest()` method as shown in the following example: + +```kotlin +package foundation.algorand.demo + +class CustomProviderService: CredentialProviderService() { + companion object { + const val GET_PASSKEY_INTENT = 1 + const val GET_PASSKEY_ACTION = "foundation.algorand.demo.GET_PASSKEY" + } + + /** + * Handle Get Credential Requests + */ + @RequiresApi(Build.VERSION_CODES.S) + override fun onBeginGetCredentialRequest( + request: BeginGetCredentialRequest, + cancellationSignal: CancellationSignal, + callback: OutcomeReceiver, + ) { + try { + callback.onResult(processGetCredentialRequest(request)) + } catch (e: GetCredentialException) { + callback.onError(GetCredentialUnknownException()) + } + } + + /** + * Get a list of available PublicKeyCredential Entries + */ + private fun processGetCredentialRequest(request: BeginGetCredentialRequest): BeginGetCredentialResponse{ + Log.v(TAG, "processing GetCredentialRequest") + val deferredCredentials: Deferred> = scope.async { + credentialRepository.getDatabase(this@LiquidCredentialProviderService).credentialDao().getAllRegular() + } + val credentials = runBlocking { + deferredCredentials.await() + } + return BeginGetCredentialResponse(credentials.map { + val data = Bundle() + data.putString("credentialId", it.credentialId) + data.putString("userHandle", it.userHandle) + PublicKeyCredentialEntry.Builder( + this@LiquidCredentialProviderService, + it.userHandle, + createNewPendingIntent(GET_PASSKEY_ACTION, GET_PASSKEY_INTENT, data), + request.beginGetCredentialOptions[0] as BeginGetPublicKeyCredentialOption + ) + .setIcon(Icon.createWithResource(this@LiquidCredentialProviderService, R.mipmap.ic_launcher)) + .build() + }) + } + + /** + * This method creates a new PendingIntent for the given action and request code. + */ + private fun createNewPendingIntent(action: String, requestCode: Int, extra: Bundle?): PendingIntent { + val intent = Intent(action).setPackage(PACKAGE_NAME) + + if (extra != null) { + intent.putExtra("CREDENTIAL_DATA", extra) + } + return PendingIntent.getActivity( + applicationContext, requestCode, + intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) + ) + } +} +``` + +## Selection + +Once you query and populate the credentials, +now you need to handle the selection phase for the credentials being selected by the user. + + +1. In the `onCreate` method of the corresponding Activity, retrieve the associated intent, and pass to [PendingIntentHandler.retrieveProviderGetCredentialRequest()](https://developer.android.com/reference/androidx/credentials/provider/ProviderGetCredentialRequest). +2. Extract the [GetPublicKeyCredentialOption](https://developer.android.com/reference/androidx/credentials/GetPublicKeyCredentialOption) from the request retrieved above. Subsequently, extract the `requestJson` and `clientDataHash` from this option. +3. Extract the `credentialId` from the intent extra, which was populated by the credential provider when the corresponding `PendingIntent` was set up. +4. Extract the passkey from your local database using the request parameters accessed above. +5. Assert that the passkey is valid with extracted metadata, and user verification. +6. Construct a JSON response based on the W3 Web Authentication Assertion spec. +7. Construct a PublicKeyCredential using the JSON generated above and set it on a final GetCredentialResponse. + + +The following example illustrates how these steps can be implemented: + + + + + + + + + + diff --git a/docs/src/content/docs/clients/android/provider-service/introduction.mdx b/docs/src/content/docs/clients/android/provider-service/introduction.mdx index 413392c..9d96105 100644 --- a/docs/src/content/docs/clients/android/provider-service/introduction.mdx +++ b/docs/src/content/docs/clients/android/provider-service/introduction.mdx @@ -1,5 +1,5 @@ --- -title: "Android: Provider Service" +title: "Android 14: Provider Service" --- import { Aside, Code, Steps } from "@astrojs/starlight/components"; @@ -15,7 +15,7 @@ This allows applications to store and manage credentials outside Google Password It opens the doors to a new world of possibilities for developers to create secure and private authentication experiences using just their Android devices. -This guide is a duplicate of the [official guide](https://developer.android.com/identity/sign-in/credential-provider) +This guide is a duplicate of the [official guide](https://developer.android.com/identity/sign-in/credential-provider) with some additional context and a focus on Passkeys. ### Who is this for?