function base64UrlEncode(buffer: ArrayBuffer) { const bytes = new Uint8Array(buffer) let binary = "" for (const b of bytes) { binary += String.fromCharCode(b) } return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "") } export function randomString(byteLength = 32) { const bytes = new Uint8Array(byteLength) crypto.getRandomValues(bytes) return base64UrlEncode(bytes.buffer) } export async function sha256Base64Url(input: string) { const data = new TextEncoder().encode(input) const digest = await crypto.subtle.digest("SHA-256", data) return base64UrlEncode(digest) } export async function createPkcePair() { const verifier = randomString(32) const challenge = await sha256Base64Url(verifier) return { verifier, challenge } }