Android: Registration
Register a Passkey with the Service and attest the knowledge of a KeyPair. This is done by creating a new Passkey with the liquid extension enabled. The extension is used to sign the challenge with an additional KeyPair as well as authenticate a remote peer.
Get started by initializing the AttestationApi with an OkHttpClient and CookieJar.
val httpClient = OkHttpClient.Builder() .cookieJar(cookieJar) // Use Cookie jar to share cookies between requests .build()val attestationApi = AttestationApi(httpClient)
👤 User Agent
The User-Agent string is used to authenticate the device.
// UA used to authenticate the deviceval userAgent = "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} " +"(Android ${Build.VERSION.RELEASE}; ${Build.MODEL}; ${Build.BRAND})"
🧮 Options
Fetch attestation options from the service. The remote client should present a Deep Link which contains the Origin.
// Create Options for FIDO2 Serverval options = JSONObject()options.put("username", account.address.toString())options.put("displayName", "Liquid Auth User")options.put("authenticatorSelection", JSONObject().put("userVerification", "required"))
// Enable Liquid Extensionval extensions = JSONObject()extensions.put("liquid", true)options.put("extensions", extensions)
val response = attestationApi.postAttestationOptions( origin, // Origin Server userAgent, // Required for checking the authenticator fingerprint options // Additional Request Options)
✨ Creating
There are several ways to handle the creation of a new Passkey. We recommend using the FIDO2ApiClient or CredentialManager
val fido2Client = Fido2ApiClient(context)
val origin = "https://my-liquid-service.com"
// Fetch Attestation Optionsval response = attestationApi.postAttestationOptions(origin, userAgent, options).await()
// Parse the response to PublicKeyCredentialCreationOptionsval pubKeyCredentialCreationOptions = response.body!!.toPublicKeyCredentialCreationOptions()
// Sign the challenge with the additional keypair you have custody ofval signature = KeyPairs.rawSignBytes( pubKeyCredentialCreationOptions.challenge, keyPair.private)
// Activity Result Handlerfun handleAuthenticatorAttestationResult(activityResult: ActivityResult){ val bytes = activityResult.data?.getByteArrayExtra(Fido.FIDO2_KEY_CREDENTIAL_EXTRA) when { activityResult.resultCode != Activity.RESULT_OK -> Log.d(TAG, "Not OK!")
bytes == null -> Log.e(TAG, "Error!")
else -> { /** * Handle the PublicKeyCredential * * Now you can combine the PublicKeyCredential with the Liquid Extension JSON * and submit it to the service for verification */ val credential = PublicKeyCredential.deserializeFromBytes(bytes) } }}
// Register/Attestation Intent Launcherval attestationIntentLauncher = registerForActivityResult( ActivityResultContracts.StartIntentSenderForResult(), ::handleAuthenticatorAttestationResult)
// Launch the FIDO2 Intentval pendingIntent = fido2Client.getRegisterPendingIntent(pubKeyCredentialCreationOptions).await()attestationIntentLauncher.launch( IntentSenderRequest.Builder(pendingIntent).build())
import foundation.algorand.auth.fido2.*
val credential = PublicKeyCredential()
🔐 Liquid Extension
Sign the challenge with an additional KeyPair and optionally authenticate a remote peer.
// Create the Liquid Extension JSONval liquidExtJSON = JSONObject()// The type of signature and public key, this is also used// to determine the type of encoding for the user.idliquidExtJSON.put("type", "algorand")// The address of the accountliquidExtJSON.put("address", account.address.toString())// The signature of the challenge, signed by the accountliquidExtJSON.put("signature", Base64.encodeBase64URLSafeString(signature))// Optionally authenticate a remote peerliquidExtJSON.put("requestId", "<UUID_FROM_QR_CODE>")// Optional device nameliquidExtJSON.put("device", Build.MODEL)
🚚 Response
val response = attestationApi.postAttestationResponse( origin, // Origin Server "User-Agent-String", // Required for checking the authenticator fingerprint credential, // PublicKeyCredential liquidExtJSON // Liquid Extension JSON)