/** * Hash a token with SHA-256 for storage in database * Never store raw tokens - always hash first * Uses Web Crypto API for Cloudflare Workers compatibility */ export const hashToken = async (token: string): Promise => { const encoder = new TextEncoder(); const data = encoder.encode(token); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = new Uint8Array(hashBuffer); return Array.from(hashArray) .map((b) => b.toString(16).padStart(2, "0")) .join(""); }; /** * Generate a session token (UUID v4) */ export const generateSessionToken = (): string => { return crypto.randomUUID(); }; /** * Generate a device fingerprint (UUID v4) */ export const generateDeviceFingerprint = (): string => { return crypto.randomUUID(); }; /** * Generate a secure random token for email verification, password reset, etc. * Uses 32 bytes (256 bits) of entropy * Uses Web Crypto API for Cloudflare Workers compatibility */ export const generateSecureToken = (): string => { const bytes = new Uint8Array(32); crypto.getRandomValues(bytes); return Array.from(bytes) .map((b) => b.toString(16).padStart(2, "0")) .join(""); }; /** * Generate expiration date */ export const generateExpiry = (seconds: number): Date => { return new Date(Date.now() + seconds * 1000); };