-
-
Notifications
You must be signed in to change notification settings - Fork 14
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
Challenge mismatch due to differing packages used for base64 encoding/decoding #7
Comments
Actually, ignore this, there's a core bug in the package niklasvh/base64-arraybuffer#42 |
Perhaps instead use https://github.com/mathiasbynens/base64 everywhere (it's browser-compatible too). |
Note that on the client-side, you can use this for converting from // <https://gist.github.com/miguelmota/5b06ae5698877322d0ca?permalink_comment_id=3611597#gistcomment-3611597>
// <https://stackoverflow.com/a/31394257>
function toArrayBuffer(buffer) {
return buffer.buffer.slice(
buffer.byteOffset,
buffer.byteOffset + buffer.byteLength
);
} |
Re-opening with a little updated recommendation list (instead of original):
|
This is what we mean by use const credential = await navigator.credentials.create({
publicKey: {
rp: {
name: 'SOME NAME'
},
user: {
id: toArrayBuffer(base64url.toBuffer(window.USER.id)),
// <https://blog.millerti.me/2023/02/14/controlling-the-name-displayed-during-webauthn-registration-and-authentication/>
name: window.USER.email,
displayName: window.USER.email
},
// https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/client_data_json.md
challenge: toArrayBuffer(base64url.toBuffer(response.body.challenge)), |
Thank you @jaredhanson for all your work here on this project and package. We're implementing it on https://forwardemail.net. Reviewed a lot of the TODO's in the codebase. Happy to help maintain the project and npm releases. We also maintain @koajs, @expressjs, @ladjs, @breejs, @cabinjs, and more. If interested, just grant npm and GitHub access to the "titanism" user, and our team at @forwardemail will help maintain (we use |
Two other issues:
|
Noticed this as well. For us, using the native "Buffer.from" instead of the third party util solved it. |
Could this be because the custom library being used (base64url) is encoding strings without the base64 padding? btoa('User:10') // 'VXNlcjoxMA=='
Buffer.from('User:10').toString('base64') // 'VXNlcjoxMA=='
base64url.encode('User:10') // 'VXNlcjoxMA' I'm only able to get the challenge to be accepted by removing the padding: Buffer.from('User:10').toString('base64').replaceAll('=', ''); If you decode the ArrayBuffers processed by this lib: new TextDecoder('utf-8').decode(base64url.decode('VXNlcjoxMA')) // 'User:10'
new TextDecoder('utf-8').decode(base64url.decode('VXNlcjoxMA==')) // 'User:10\x00\x00' If I instead use atob to create the arraybuffer: function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
} and then I use TextDecoder to convert those from ArrayBuffers, I see a more consistent result (because it respects the paddings): new TextDecoder('utf-8').decode(base64ToArrayBuffer('VXNlcjoxMA')) // 'User:10'
new TextDecoder('utf-8').decode(base64ToArrayBuffer('VXNlcjoxMA==')) // 'User:10' So it seems you can use Buffer.from(str).toString('base64') on the server side, and then you just need to make sure you account for the paddings on the client side as well when doing navigator.credentials.create. With these 2x helper functions in the browser for ArrayBuffer I'm getting it consistently working: function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
} return navigator.credentials.create({
publicKey: {
rp: {
name: 'Todos'
},
user: {
id: base64ToArrayBuffer(json.user.id),
name: json.user.name,
displayName: json.user.displayName
},
challenge: base64ToArrayBuffer(json.challenge), and later: .then(function(credential) {
var body = {
response: {
clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON),
attestationObject: arrayBufferToBase64(credential.response.attestationObject)
}
}; Edit: ok it seems base64url is a thing as well, my bad.. but you can do it in Node at least with |
Hi there - this project uses
base64url
on server-side and on client-side the demo usesbase64-arraybuffer
(albeit an outdated version). A new version ofbase64-arraybuffer
is at https://github.com/niklasvh/base64-arraybuffer.We recommend a few things:
base64url
, usebase64-arraybuffer
from npm insteadtoBuffer
method in existing instances, simply usedecode
The text was updated successfully, but these errors were encountered: