A comprehensive TypeScript library providing both client-side and server-side WebAuthn functionality for implementing passwordless authentication with passkeys and other WebAuthn-compatible authenticators
Utilities for converting between Base64URL strings and ArrayBuffers, essential for WebAuthn data handling. WebAuthn APIs use ArrayBuffers, but JSON serialization requires string encoding, making these conversion functions crucial for client-server communication.
Converts a Base64URL-encoded string to an ArrayBuffer for use with WebAuthn APIs.
/**
* 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`
* @param base64URLString The Base64URL-encoded string to convert
* @returns ArrayBuffer containing the decoded binary data
*/
function base64URLStringToBuffer(base64URLString: string): ArrayBuffer;Usage Examples:
import { base64URLStringToBuffer } from "@simplewebauthn/browser";
// Convert challenge from server JSON to ArrayBuffer for WebAuthn
const challengeString = "dGVzdC1jaGFsbGVuZ2U"; // From server JSON
const challengeBuffer = base64URLStringToBuffer(challengeString);
// Convert user ID from server JSON to ArrayBuffer
const userIdString = "dXNlci0xMjM0NTY"; // From server JSON
const userIdBuffer = base64URLStringToBuffer(userIdString);
// Convert credential IDs for allowCredentials/excludeCredentials
const credentialIds = [
"Y3JlZGVudGlhbC0xMjM0NTY",
"YW5vdGhlci1jcmVkZW50aWFsLTc4OQ"
];
const allowCredentials = credentialIds.map(id => ({
type: "public-key" as const,
id: base64URLStringToBuffer(id),
transports: ["usb", "nfc", "ble", "hybrid"] as const,
}));
console.log("Converted credential IDs:", allowCredentials);This function handles the Base64URL to Base64 conversion (replacing - with + and _ with /), adds proper padding, and converts the decoded binary string to an ArrayBuffer via Uint8Array.
Converts an ArrayBuffer to a Base64URL-encoded string suitable for JSON serialization and server transmission.
/**
* 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`
* @param buffer The ArrayBuffer to convert
* @returns Base64URL-encoded string suitable for JSON transmission
*/
function bufferToBase64URLString(buffer: ArrayBuffer): string;Usage Examples:
import { bufferToBase64URLString } from "@simplewebauthn/browser";
// Convert WebAuthn response data for server transmission
const credential = await navigator.credentials.create(options);
const registrationResponse = {
id: credential.id,
rawId: bufferToBase64URLString(credential.rawId),
response: {
clientDataJSON: bufferToBase64URLString(credential.response.clientDataJSON),
attestationObject: bufferToBase64URLString(credential.response.attestationObject),
},
type: credential.type,
};
// Send to server as JSON
await fetch("/webauthn/register/finish", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(registrationResponse),
});
// Convert authentication response data
const authCredential = await navigator.credentials.get(authOptions);
const authResponse = {
id: authCredential.id,
rawId: bufferToBase64URLString(authCredential.rawId),
response: {
clientDataJSON: bufferToBase64URLString(authCredential.response.clientDataJSON),
authenticatorData: bufferToBase64URLString(authCredential.response.authenticatorData),
signature: bufferToBase64URLString(authCredential.response.signature),
userHandle: authCredential.response.userHandle
? bufferToBase64URLString(authCredential.response.userHandle)
: undefined,
},
};
console.log("Authentication response:", authResponse);This function converts the ArrayBuffer to a Uint8Array, builds a binary string, encodes it with btoa(), and then converts from Base64 to Base64URL format (replacing + with -, / with _, and removing padding = characters).
These utilities are essential for the WebAuthn data flow:
import {
base64URLStringToBuffer,
bufferToBase64URLString,
startRegistration
} from "@simplewebauthn/browser";
// 1. Server sends JSON with Base64URL-encoded data
const serverOptions = {
challenge: "dGVzdC1jaGFsbGVuZ2U",
user: {
id: "dXNlci0xMjM0NTY",
name: "testuser",
displayName: "Test User"
},
// ... other options
};
// 2. Library converts to WebAuthn format internally
const webauthnOptions = {
challenge: base64URLStringToBuffer(serverOptions.challenge),
user: {
...serverOptions.user,
id: base64URLStringToBuffer(serverOptions.user.id),
},
// ... other conversions
};
// 3. WebAuthn API returns ArrayBuffers
const credential = await navigator.credentials.create({ publicKey: webauthnOptions });
// 4. Library converts back to Base64URL for JSON transmission
const response = {
id: credential.id,
rawId: bufferToBase64URLString(credential.rawId),
response: {
clientDataJSON: bufferToBase64URLString(credential.response.clientDataJSON),
attestationObject: bufferToBase64URLString(credential.response.attestationObject),
},
};
// 5. Send JSON to server
await fetch("/webauthn/register/finish", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(response),
});Base64URL is a variant of Base64 encoding that's URL and filename safe:
+, /, and = for padding-, _, and no paddingWebAuthn specifications use Base64URL encoding for JSON serialization because:
// Example of the difference:
const buffer = new ArrayBuffer(16);
const view = new Uint8Array(buffer);
view.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
// Standard Base64 (hypothetical)
// "AQIDBAUGBwgJCgsMDQ4PEA=="
// Base64URL (actual result)
// "AQIDBAUGBwgJCgsMDQ4PEA"
const base64url = bufferToBase64URLString(buffer);
console.log("Base64URL:", base64url); // No padding, URL-safe charsThese functions are optimized for typical WebAuthn data sizes:
For large data sets, consider streaming approaches, but WebAuthn data rarely exceeds a few KB per operation.
Both functions are designed to be robust:
try {
const buffer = base64URLStringToBuffer(invalidString);
} catch (error) {
console.error("Invalid Base64URL string:", error);
}
try {
const string = bufferToBase64URLString(buffer);
console.log("Conversion successful:", string);
} catch (error) {
console.error("Buffer conversion failed:", error);
}The functions will throw standard JavaScript errors for invalid inputs like malformed Base64URL strings or invalid ArrayBuffers.
Install with Tessl CLI
npx tessl i tessl/npm-simplewebauthn--browser