android / identity-samples

Multiple samples showing the best practices in identity on Android.
Apache License 2.0
372 stars 223 forks source link

Webview Passkey creation does not take into account the ExcludedCredentials during the creation of a passkey #89

Closed amoral closed 1 month ago

amoral commented 3 months ago

For the WebView passkey functionality I followed the official documentation: https://developer.android.com/identity/sign-in/credential-manager-webview

How to reproduce: I create a passkey in the device inside our app (WebView). I can the create another one. The second invocation of the create has as an effect to substitute the existing credential in the authenticator with a new one. On the server side (RP) we have an additional credential. Of course only the newer works. Debugging the app, at the CredentialManagerHander createPasskey (https://github.com/android/identity-samples/blob/main/CredentialManagerWebView/CredentialManagerHandler.kt) the request has the ExcludedCredential table, with the entries expected, but the public key is empty. The RP sends valid values, as this works on all platform and also on the Android's Chrome. I have tested it with android chrome and it works as expected. The authenticator in this case rejects the credential creation as it holds an existing credential.

It seems that the injected javascript does not parse correctly these values. (The injected javascript: https://github.com/android/identity-samples/blob/main/CredentialManagerWebView/javascript/encode.js)

amoral commented 2 months ago

Hello, I fixed the double registration error, by adding to the injected javascript (encode.js) at the "create" function this code:

if (temppk.hasOwnProperty('excludeCredentials')) { const excludeCredentials = temppk.excludeCredentials;

        // Map over each item in the excludeCredentials array and check if it's a public key credential
        temppk.excludeCredentials = excludeCredentials.map((item, index) => {
          if (item.hasOwnProperty('id')) { 
            // If it's an object with a rawId property, just encode its value as Base64
            item.id = CM_base64url_encode(item.id);
          } else if (item.hasOwnProperty('type')){
            item.type = item.type;
          }
          return item;
        });
      }

this checks the values of the excludeCredentials and encodes the id to base64. Minify the encode.js and set it at the PasskeyWebListener.kt as the INJECTED_VAL

Sakis

niharika2810 commented 1 month ago

Hey

Thanks for sharing, would you mind creating a bug with all details required in that template? Sharing here : https://issuetracker.google.com/issues/new?component=1301097&template=1773864

Closing from here to track the bug on bug component. Hope that is fine. pelase feel free to reopen if there's anything