Edit Start
If you are just trying to test the new FIDO cross device authentication flow using your phone,
Yes that is exactly what I'm trying to achieve. I have now rolled back to just: -
- Bluetooth enabled on my Android phone
- Bluetooth visible
- Logged in to Google account both PC/Chrome and Phone
- Windows hello PIN set for my windows account
But all the bellow code gives me is the option to enter my PIN no "Add a new Android phone"
"You are mixing a few different things here. The security key, local platform authenticator (Windows Hello) and your phone will all have their own credential."
I'm sure you're correct. I was just pulling all the leavers I knew trying to make it work:- Windows Phone Link, Acccount.Live.Com account options, etc
do not require a resident credential (not yet supported) and do not set an attachment preference.
Not sure what that means. If you mean the USB key then fine I don't want to use it, but I was getting prompted for it. (See below)
When prompted in Chrome, add your phone to link it, scan the QR on your phone and then perform the UV gesture.
Ok, what QR code reader are you using?
My problem is Chrome is not prompting me to add a phone :-( There's a configuration or API argument I'm missing?
Please help.
Edit End
I understand the "available for developers later this year" caveat, but as a FIDO devotee I have been very excited about the previewed functionality from
So while I willing acknowledge/concede this is "emerging" technology: -
- Why does Create prompt for a PIN and not a fingerprint
- I've tried setting various Google account options and Windows Live options and Windows/Accounts options; which are in play?
- My phone is paired with Windows/Bluetooth; is this not enough for Chrome?
- If I choose "Add a new Android phone" I get the dinosaur QRCode. On my phone Samsung browser is my only QRC reader which returns FIDO:/484543913687778941263973123987003762051850670080716404329165 . . . Chrome does not recognize it; where does it go?
- Here is Android/Samsumg prompting me for my
Please see source code below.
const utf8Decoder = new TextDecoder('utf-8');
async function verifyCredential() {
var keyResult = await getKey();
var serverChallenge = JSON.parse(keyResult);
var credentialId = localStorage.getItem("credentialId");
if (!credentialId) {
throw new Error("You must create a Credential first");
}
var allowCredentials = [{
type: "public-key",
id: Uint8Array.from(atob(credentialId), x => x.charCodeAt(0)).buffer
}]
var getAssertionOptions = {
timeout: 30000,
challenge: Uint8Array.from(serverChallenge.Token, c => c.charCodeAt(0)).buffer,
allowCredentials: allowCredentials,
userVerification: "required"
};
return navigator.credentials.get({
publicKey: getAssertionOptions
}).then(rawAssertion => {
var assertion = {
id: base64encode(rawAssertion.rawId),
clientDataJSON: utf8Decoder.decode(rawAssertion.response.clientDataJSON),
userHandle: base64encode(rawAssertion.response.userHandle),
signature: base64encode(rawAssertion.response.signature),
authenticatorData: base64encode(rawAssertion.response.authenticatorData)
};
// Check id = allowcredentials.id
console.log("=== Assertion response ===");
console.log(assertion);
verifyAssertion(assertion).then(
result => {
var res = JSON.parse(result);
console.log(res.success);
if (res.success) {
}
});
return;
}).catch(
(err) => {
if (err.name == "NotAllowedError") {
console.log("here " err.name);
} else {
console.log("other " err.name);
}
return Promise.resolve(false);
});
}
async function createCredential() {
var keyResult = await getKey();
var serverChallenge = JSON.parse(keyResult);
var createCredentialOptions = {
rp: {
name: "WebAuthn Sample App",
icon: ""
},
user: {
id: Uint8Array.from("some.user.guid", c => c.charCodeAt(0)),
name: "[email protected]",
displayName: "Richard Maher",
icon: ""
},
pubKeyCredParams: [
{
//External authenticators support the ES256 algorithm
type: "public-key",
alg: -7
},
{
//Windows Hello supports the RS256 algorithm
type: "public-key",
alg: -257
}
],
authenticatorSelection: {
//Select authenticators that support username-less flows
//requireResidentKey: true,
//Select authenticators that have a second factor (e.g. PIN, Bio) "preferred" "discouraged"
userVerification: "required",
//Selects between bound or detachable authenticators
authenticatorAttachment: "platform" // Optional
},
//Since Edge shows UI, it is better to select larger timeout values
timeout: 30000,
//an opaque challenge that the authenticator signs over
challenge: Uint8Array.from(serverChallenge.Token, c => c.charCodeAt(0)).buffer,
//prevent re-registration by specifying existing credentials here
excludeCredentials: [],
//specifies whether you need an attestation statement
attestation: "none"
};
const authAbort = new AbortController();
const abortSignal = authAbort.signal;
abortSignal.addEventListener("abort", (e) => { console.log("It has been aborted"); });
return navigator.credentials.create({
publicKey: createCredentialOptions,
signal: abortSignal
}).then(rawAttestation => {
var attestation = {
id: base64encode(rawAttestation.rawId),
clientDataJSON: utf8Decoder.decode(rawAttestation.response.clientDataJSON),
attestationObject: base64encode(rawAttestation.response.attestationObject)
};
console.log("=== Attestation response ===");
console.log(attestation);
verifyCredentials(attestation).then(
result => {
var res = JSON.parse(result);
console.log(res.success);
if (res.success) {
localStorage.setItem("credentialId", res.id);
}
});
return;
}).catch(
(err) => {
if (err.name == "NotAllowedError") {
console.log("here " err.name);
} else {
console.log("other " err.name);
}
return Promise.resolve(false);
});
}
async function verifyCredentials(attestation) {
let params = JSON.stringify(attestation);
let resp = await fetch("api/fido/verifycredentials", {
method: "POST",
headers: { "Content-type": "application/json", "Accept": "application/json" },
body: params
});
var myStat;
if (resp.ok) {
myStat = await resp.json();
console.log("Stat vc = " myStat)
} else {
console.log("boom");
}
console.log("done ");
return myStat;
}
async function verifyAssertion(assertion) {
let params = JSON.stringify(assertion);
let resp = await fetch("api/fido/verifyassertion", {
method: "POST",
headers: { "Content-type": "application/json", "Accept": "application/json" },
body: params
});
var myStat;
if (resp.ok) {
myStat = await resp.json();
console.log("Stat va = " myStat)
} else {
console.log("boom");
}
console.log("done ");
return myStat;
}
async function getKey() {
let resp = await fetch("api/fido/getkey", {
method: "GET",
headers: { "Content-type": "application/json", "Accept": "application/json" }
});
var mykey;
if (resp.ok) {
mykey = await resp.json();
console.log("key = " mykey)
} else {
throw new Error("boom");
}
console.log("done key");
return mykey;
}
function base64encode(arrayBuffer) {
if (!arrayBuffer || arrayBuffer.length == 0)
return undefined;
return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}
CodePudding user response:
You are mixing a few different things here. The security key, local platform authenticator (Windows Hello) and your phone will all have their own credential.
If you are just trying to test the new FIDO cross device authentication flow using your phone, do not require a resident credential (not yet supported) and do not set an attachment preference.
When prompted in Chrome, add your phone to link it, scan the QR on your phone and then perform the UV gesture.