Skip to content

Instantly share code, notes, and snippets.

@Zmetser
Last active September 24, 2024 18:12
Show Gist options
  • Save Zmetser/a25cbcea15560664906dbfad555c6b3a to your computer and use it in GitHub Desktop.
Save Zmetser/a25cbcea15560664906dbfad555c6b3a to your computer and use it in GitHub Desktop.
const registerURL = "https://level2.d13s.com/m/webauthn/register";
const authURL = "https://level2.d13s.com/m/webauthn/authenticate";
const appToken = "D-lnChRTnKj9eMhmqiIhHEFoo/ER3G8d1Ke4oezHpq1MA";
async function register() {
const response = (await getRegisterChallenge()).request;
console.log("register response", response);
const credential = await createCredential(response);
console.log("credential", credential);
const finishResponse = await finishRegistration(response, credential);
console.log("finish response", await finishResponse.json());
}
async function getRegisterChallenge() {
const response = await fetch(registerURL, {
method: "POST",
headers: {
Authorization: `Bearer ${appToken}`,
},
});
return await response.json();
}
async function createCredential(response) {
const { publicKeyCredentialCreationOptions: credentialOptions } = response;
const request = {
publicKey: {
rp: { id: credentialOptions.rp.id, name: credentialOptions.rp.name },
user: {
id: base64urlToBuffer(credentialOptions.user.id),
name: credentialOptions.user.name,
displayName: credentialOptions.user.displayName,
},
challenge: base64urlToBuffer(credentialOptions.challenge),
pubKeyCredParams: credentialOptions.pubKeyCredParams,
},
};
console.log("our create request", request);
return navigator.credentials.create(request);
}
async function finishRegistration(response, credential) {
const body = {
requestId: response.requestId,
credential: {
id: credential.id,
rawId: bufferToBase64url(credential.rawId),
type: credential.type,
clientExtensionResults: {},
response: {
attestationObject: bufferToBase64url(
credential.response.attestationObject
),
clientDataJSON: bufferToBase64url(credential.response.clientDataJSON),
},
},
sessionToken: response.sessionToken || null,
};
console.log("our response", body);
return await fetch(registerURL + "/finish", {
method: "POST",
body: JSON.stringify(body),
headers: {
Authorization: `Bearer ${appToken}`,
},
});
}
async function auth() {
const response = (await getAuthChallenge()).request;
console.log("auth response", response);
const credential = await authCredential(response);
console.log("credential", credential);
const finishResponse = await finishAuth(response, credential);
console.log("finish response", await finishResponse.json());
}
async function getAuthChallenge() {
const response = await fetch(authURL, {
method: "POST",
});
return await response.json();
}
async function authCredential(response) {
const { publicKeyCredentialRequestOptions } = response;
const request = {
publicKey: {
challenge: base64urlToBuffer(publicKeyCredentialRequestOptions.challenge),
rpid: publicKeyCredentialRequestOptions.rpId,
},
};
console.log("our get request", request);
return navigator.credentials.get(request);
}
async function finishAuth(response, credential) {
const body = {
requestId: response.requestId,
credential: {
id: credential.id,
rawId: bufferToBase64url(credential.rawId),
type: credential.type,
response: {
authenticatorData: bufferToBase64url(
credential.response.authenticatorData
),
signature: bufferToBase64url(credential.response.signature),
clientDataJSON: bufferToBase64url(credential.response.clientDataJSON),
userHandle: bufferToBase64url(credential.response.userHandle),
},
clientExtensionResults: {},
},
};
console.log("our response", body);
return await fetch(authURL + "/finish", {
method: "POST",
body: JSON.stringify(body),
});
}
function base64urlToBuffer(baseurl64String) {
const padding = "==".slice(0, (4 - (baseurl64String.length % 4)) % 4);
const base64String =
baseurl64String.replace(/-/g, "+").replace(/_/g, "/") + padding;
const str = atob(base64String);
const buffer = new ArrayBuffer(str.length);
const byteView = new Uint8Array(buffer);
for (let i = 0; i < str.length; i++) {
byteView[i] = str.charCodeAt(i);
}
return buffer;
}
function bufferToBase64url(buffer) {
const byteView = new Uint8Array(buffer);
let str = "";
for (const charCode of byteView) {
str += String.fromCharCode(charCode);
}
const base64String = btoa(str);
const base64urlString = base64String
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
return base64urlString;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment