Docs
Frontend Requirements
Last modified on October 24, 2025 • 3 min read • 504 wordsThe website’s frontend plays the following roles in facilitating use of WebAuthn:
- Call
navigator.credentials.create() - Send the registration response to the server
- Call
navigator.credentials.get() - Send the authentication response to the server
The guidance below identifies best practices to fulfill these responsibilities and securely incorporate passkeys-based authentication into your website.
Using JSON between frontend and backend
Some of the options that get passed in to WebAuthn’s navigator.credentials.create()
and navigator.credentials.get() must be of type Uint8Array. Unfortunately Uint8Array values
do not serialize well into a JSON representation, making it tricky to receive and send them
between the backend to the frontend.
It is suggested that options and responses be shuttled between frontend and backend using
Base64URL encoding on Uint8Array values. Base64URL string representations of these values
are easier to transmit when passed back and forth as JSON.
The following base64URLStringToBuffer() and bufferToBase64URLString() methods
can be used to account for the lack of native JavaScript support
in web platforms to encode and decode between Uint8Array and Base64URL string values:
base64URLStringToBuffer()
/**
* Convert from a Base64URL-encoded string to an Array Buffer. Best used when converting a
* credential ID from a JSON string to an ArrayBuffer, like in allowCredentials or
* excludeCredentials
*
* Helper method to compliment `bufferToBase64URLString`
*/
export function base64URLStringToBuffer(base64URLString: string): ArrayBuffer {
// Convert from Base64URL to Base64
const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
/**
* Pad with '=' until it's a multiple of four
* (4 - (85 % 4 = 1) = 3) % 4 = 3 padding
* (4 - (86 % 4 = 2) = 2) % 4 = 2 padding
* (4 - (87 % 4 = 3) = 1) % 4 = 1 padding
* (4 - (88 % 4 = 0) = 4) % 4 = 0 padding
*/
const padLength = (4 - (base64.length % 4)) % 4;
const padded = base64.padEnd(base64.length + padLength, '=');
// Convert to a binary string
const binary = atob(padded);
// Convert binary string to buffer
const buffer = new ArrayBuffer(binary.length);
const bytes = new Uint8Array(buffer);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return buffer;
}bufferToBase64URLString()
/**
* Convert the given array buffer into a Base64URL-encoded string. Ideal for converting various
* credential response ArrayBuffers to string for sending back to the server as JSON.
*
* Helper method to compliment `base64URLStringToBuffer`
*/
export function bufferToBase64URLString(buffer: ArrayBuffer): string {
const bytes = new Uint8Array(buffer);
let str = '';
for (const charCode of bytes) {
str += String.fromCharCode(charCode);
}
const base64String = btoa(str);
return base64String.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}1. Call navigator.credentials.create()
TODO
2. Send the registration response to the server
TODO
3. Call navigator.credentials.get()
TODO
4. Send the authentication response to the server
TODO