Android FIDO2 API Demo
Background
On the 25th of February 2019, the FIDO Alliance announced that any device running Android 7.0+ is now FIDO2 Certified out of the box.
The FIDO2 APIs for android were updated December 2018 but I could not find any examples showing how to use it. There is a sample project for Fido U2F and a one liner that says: “The FIDO2 API can be integrated into your Android app in a similar fashion”, but it is not that easy.
I have created a small app that demos how to use these APIs with local hard coded options. In reality these options would come from a FIDO2 server. There are a few websites where you can play with FIDO2 on your desktop and mobile browser already, such as webauthn.io.
The Code
To get started on Android you need to include the play-services-fido library as a dependency.
implementation 'com.google.android.gms:play-services-fido:17.0.0'
You will then need to create PublicKeyCredentialCreationOptions. For the API demo the specific values you set here do not matter too much, and in practice you will just set whatever you receive from your server. I used these values:
The biggest stumbling block here is the PublicKeyCredentialRpEntity ID. I will go into more detail about this at the end of this post when I discuss the Relying Party ID.
Next you will need to get a FIDO2 pending intent for registration with these options and launch it.
This will give the UI over to play-services-fido.
You will receive the result in
onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?)
and can parse it from the intent with
All these fields would now be sent to your server for validation and storage. The key handle would be used to request signing by this key.
Now we wil create PublicKeyCredentialRequestOptions, again all these options would usually come from your server.
Then get a FIDO2 pending intent for signing with these options,
launch the pending intent and see:
You will again receive the result in
onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?)
and can parse it from the intent with
Relying Party ID
If you look at documentation for MakeCredentialOptions.Builder, go to Public Methods and then the setRp method you will see:
Note: the RpId should be an effective domain (aka, without scheme or port); and it should also be in secure context (aka https connection). Apps-facing API needs to check the package signature against Digital Asset Links, whose resource is the RP ID with prepended “//”.
So for Android apps you need to host an assetlinks.json file on https://<rp_id>/.well-known/assetlinks.json to allow the app to use the FIDO2 APIs to register and sign credentials for that domain.
For this sample app I have set the RP ID to strategics-fido2.firebaseapp.com and I am hosting this assetlinks.json:
on https://strategics-fido2.firebaseapp.com/.well-known/assetlinks.json where package_name matches the applicationId in my build.gradle and the sha256_cert_fingerprints matches the fingerprint of my signing key.
The fingerprint can be found various ways as described in this Stack Overflow post or if you are using App Signing, on the app signing page of the Play Console.
There is a Firebase Hosting project included in my sample repo that can host the assetlinks.json for you.
What Now?
The code for this post is available on GitHub. You should be able to clone it and it should just work.
If you want some more information on FIDO2, WebAuthn and CTAP2, you can visit their respective websites. You can watch a few FIDO2 demos on YouTube
Update April 2019
Google has released official docs and a sample project
Update May 2019
Google released a codelab