svelte-guardian
Version:
Batteries included authentication for SvelteKit applications.
160 lines (159 loc) • 5.31 kB
JavaScript
import { goto } from '$app/navigation';
// Utility function for API calls
async function apiCall(endpoint, method = 'POST', data) {
try {
const response = await fetch(`/auth/${endpoint}`, {
method,
headers: {
'Content-Type': 'application/json'
},
body: data ? JSON.stringify(data) : undefined
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Request failed');
}
return await response.json();
}
catch (error) {
return {
success: false,
error: error.message || 'An error occurred'
};
}
}
// Email Verification Functions
export const emailVerification = {
// Request OTP verification
async requestOTP(email) {
return await apiCall('verify-email/send-otp', 'POST', { email });
},
// Request link
async requestLink(email) {
return await apiCall('verify-email/send-link', 'POST', { email });
},
// Initiate email verification
async initiate(email) {
return await apiCall('verify-email/initiate', 'POST', { email });
},
// Verify OTP
async verifyOTP(email, otp) {
return await apiCall('verify-email/verify-otp', 'POST', { email, otp });
},
// Verify link token
async verifyToken(email, token) {
return await apiCall('verify-email/verify-token', 'POST', { email, token });
},
// Utility function to handle email verification flow
async handleEmailVerification(email, method) {
if (method === 'otp') {
const result = await this.requestOTP(email);
if (result.success) {
// Show OTP input form
return {
success: true,
data: { verificationId: result.data?.verificationId }
};
}
return result;
}
else {
return await this.requestLink(email);
}
}
};
// Password Reset Functions
export const passwordReset = {
// Request password reset
async requestReset(email) {
return await apiCall('reset-password/initiate-reset', 'POST', { email });
},
// Validate reset token
async validateToken(token) {
return await apiCall('reset-password/validate-token', 'POST', { token });
},
// Reset password
async resetPassword(email, token, newPassword, confirmPassword) {
if (newPassword !== confirmPassword) {
return {
success: false,
error: 'Passwords do not match'
};
}
return await apiCall('reset-password/reset', 'POST', {
email,
token,
newPassword
});
},
// Password validation
validatePassword(password, options = {}) {
const errors = [];
if (password.length < (options.minimumPasswordLength || 8)) {
errors.push(`Password must be at least ${options.minimumPasswordLength || 8} characters long`);
}
if (options.requireSpecialChar && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
errors.push('Password must contain at least one special character');
}
if (options.requireNumber && !/\d/.test(password)) {
errors.push('Password must contain at least one number');
}
if (options.requireUppercase && !/[A-Z]/.test(password)) {
errors.push('Password must contain at least one uppercase letter');
}
return {
valid: errors.length === 0,
errors
};
},
// Complete password reset flow
async handlePasswordReset(email) {
const result = await this.requestReset(email);
if (result.success) {
// Redirect to check email page
await goto('/auth/check-email');
}
return result;
}
};
// Two-Factor Authentication Functions
export const twoFactorAuth = {
// Setup 2FA
async setup(method) {
return await apiCall('two-factor/setup', 'POST', { method });
},
// Generate QR code for TOTP
async generateQRCode(secret) {
const qrcode = await import('qrcode');
const otpauth = `otpauth://totp/${window.location.hostname}?secret=${secret}`;
return await qrcode.toDataURL(otpauth);
},
// Verify 2FA token
async verifyToken(token) {
return await apiCall('two-factor/verify', 'POST', { token });
},
// Verify backup code
async verifyBackupCode(code) {
return await apiCall('two-factor/verify-backup', 'POST', { code });
},
// Disable 2FA
async disable() {
return await apiCall('two-factor/disable', 'POST');
},
// Handle complete 2FA setup flow
async handleSetup(method) {
const result = await this.setup(method);
if (result.success && method === '2fa-totp') {
const qrCode = await this.generateQRCode(result.data.secret);
return {
...result,
data: {
...result.data,
qrCode
}
};
}
return result;
}
};
export * from '@auth/sveltekit/client';