Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api.CredentialsContainer.get.publicKey_option.extensions - largeBlob not working on Chrome Android (130) #25002

Open
flAIght-dev opened this issue Nov 8, 2024 · 1 comment
Labels
data:api 🐇 Compat data for Web APIs. https://developer.mozilla.org/docs/Web/API

Comments

@flAIght-dev
Copy link

flAIght-dev commented Nov 8, 2024

What type of issue is this?

Incorrect support data (example: BrowserX says "86" but support was added in "40")

What information was incorrect, unhelpful, or incomplete?

largeBlob extension is reported as supported on Android Chrome since 113. Testing it on 130 I am not able to use it.

What browsers does this problem apply to, if applicable?

Chromium (Chrome, Edge 79+, Opera, Samsung Internet)

What did you expect to see?

I expected to be able to read and write a blob

Did you test this? If so, how?

The credential is created without errors. On the write call "written" is undefined. No errors in the read call but the blob is (obviously) empty.

Here is the test code:


  let username = "test"
  let name = "test name"

  const firstSalt = new Uint8Array(new Array(32).fill(1)).buffer;

  navigator.credentials.create({
    publicKey: {
      challenge: Uint8Array.from([1, 2, 3, 4]),
        rp: {
            name: "Example RP",
            id: "api.test.org",
        },
      user: {
        id: Uint8Array.from(username.split("").map(c => c.codePointAt(0))),
        name: name,
        displayName: name,
      },
        pubKeyCredParams: [
            { alg: -8, type: "public-key" },   // Ed25519
            { alg: -7, type: "public-key" },   // ES256
            { alg: -257, type: "public-key" }, // RS256                        
        ],
        authenticatorSelection: {
            userVerification: "required",
            residentKey: "required",
            //requireResidentKey: true
        },

      extensions: {
        prf: {
            eval: {
                first: firstSalt,
            },
        },
        largeBlob: {
          support: "required",
        },
        "credProps": true
      }
    }
  }).then(credential => {
    console.log(credential);
    console.log(credential.getClientExtensionResults());
    window.localStorage.credentialId = arrayBufferToBase64(credential.rawId);

    console.log("Credential successfully created! Try logging in.");

    console.log("extension results " + JSON.stringify(credential.getClientExtensionResults()));

  }).catch(error => {
    console.log(error.toString());
  });

Read blob

navigator.credentials.get({

   publicKey: {
       challenge: new Uint8Array([1, 2, 3, 4]), // Example value
       rp: {
           name: "Example RP",
           id: "api.test.org",
       },
       user: {
           id: Uint8Array.from(username, c => c.charCodeAt(0)), // User-provided ID
           name: username,
           displayName: name,
       },
       pubKeyCredParams: [
           { alg: -8, type: "public-key" },   // Ed25519
           { alg: -7, type: "public-key" },   // ES256
           { alg: -257, type: "public-key" }, // RS256                        
       ],
       authenticatorSelection: {
           userVerification: "required",
           residentKey: "required"
       },
     extensions: {
       largeBlob: {
         read: true
       }
     }
   }

 }).then(assertion => {
   console.log("Blob read", assertion);
   console.log(assertion.getClientExtensionResults());

   console.log("assertion " + assertion);
   console.log("extension results " + JSON.stringify(assertion.getClientExtensionResults()));

   if (assertion.getClientExtensionResults().largeBlob) {
     console.log("Blob found");
     let blobContent = assertion.getClientExtensionResults().largeBlob;
     console.log("blobContent " + blobContent);
     console.log("blobContent type " + (typeof blobContent));
     console.log("blobContent type 2 " + Object.prototype.toString.call(blobContent));
     console.log("blobContent stringify " + JSON.stringify(blobContent));
     let blobString = new TextDecoder().decode(blobContent.blob);
     console.log("blobString: " + blobString);
     console.log("Blob: ", blobString);
     console.log("Blob read successfully! Content: " + blobString);
   } else {
     console.log("No blob found.");
   }
 }).catch(error => {
   console.log(error.toString());
 });

Write blob


  let blobValue = "test blob value"
  
  const blob = new TextEncoder().encode(blobValue);

  console.log("Blob write content: " + blobValue);
  console.log("Blob write content length: " + blob.length);
  console.log("Blob write content encoded: " + Object.prototype.toString.call(blob));

  navigator.credentials.get({
    publicKey: {
        challenge: new Uint8Array([1, 2, 3, 4]), // Example value
        rp: {
            name: "Example RP",
            id: "api.test.org",
        },
        user: {
            id: Uint8Array.from(username, c => c.charCodeAt(0)), // User-provided ID
            name: username,
            displayName: name,
        },
        pubKeyCredParams: [
            { alg: -8, type: "public-key" },   // Ed25519
            { alg: -7, type: "public-key" },   // ES256
            { alg: -257, type: "public-key" }, // RS256                        
        ],
        authenticatorSelection: {
            userVerification: "required",
            residentKey: "required"
        },
      extensions: {
        largeBlob: {
          write: blob
        }
      }
    }
  }).then(assertion => {
    console.log("Blob write attempt", assertion);
    console.log(assertion.getClientExtensionResults());

    if (assertion.getClientExtensionResults().largeBlob.written) {
      console.log("Blob written");
      console.log("Blob written successfully!");

      console.log("write blob stringify " + JSON.stringify(assertion.getClientExtensionResults()));

    } else {
      console.log("Blob not written");
      console.log("Failed to write blob.");
    }
  }).catch(error => {
    console.log(error.toString());
  });

Can you link to any release notes, bugs, pull requests, or MDN pages related to this?

No response

Do you have anything more you want to share?

The same code works fine with Chrome on iOS.

MDN URL

https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API/WebAuthn_extensions

MDN metadata

MDN page report details
  • Query: api.CredentialsContainer.get.publicKey_option.extensions
  • Report started: 2024-11-08T12:29:50.653Z
@queengooborg queengooborg added the data:api 🐇 Compat data for Web APIs. https://developer.mozilla.org/docs/Web/API label Nov 9, 2024
@IanNicki
Copy link

IanNicki commented Nov 20, 2024

Just found another problem on the iOS side in combination with Chrome > 130:

  • Chrome 131.0. 6778.73
  • iOS 17.7.1
  • Token2 T2F2-PIN+ (FIDO key supporting LargeBlobs)

As reported by @flAIght-dev, reading and writing to LargeBlobs on iOS devices using Chrome is possible. The problem is that only a passkey stored in the iCloud keychain is supported.
Selecting a FIDO2 key as "Other Sign In Option" fails with the error message "Large blob is undefined -- your browser probably doesn't know about it" on the testing website.

I can't tell if this is due to Chrome on iOS or the iOS CTAP implementation. Does anyone know how to find this out?

By the way, the Passkey Spotlight Week has just started for Android and Chrome development. I have already posted a question concerning the LargeBlob support topic in Android. Maybe you should post a short question on this topic as well.
They will be answering some of them this Thursday (21/11/24) on their Youtube Livestream Channel.
Questions can be submitted in the comments or via their feedback form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
data:api 🐇 Compat data for Web APIs. https://developer.mozilla.org/docs/Web/API
Projects
None yet
Development

No branches or pull requests

3 participants