UNPKG

svelte-guardian

Version:

Batteries included authentication for SvelteKit applications.

106 lines (105 loc) 4.76 kB
import GoogleProvider from '@auth/core/providers/google'; import GitHubProvider from '@auth/core/providers/github'; import CredentialsProvider from '@auth/core/providers/credentials'; import { validateCredentials } from '../utils/validation'; import { verifyPassword } from '../utils/security'; import { AuthenticationError } from './errors'; export function createProviders(providerConfig, securityConfig, adapter) { const providers = []; // Google Provider if (providerConfig.google?.enabled !== false) { providers.push(GoogleProvider({ clientId: providerConfig?.google?.clientId, clientSecret: providerConfig?.google?.clientSecret, authorization: { params: { prompt: 'consent', access_type: 'offline', response_type: 'code' } } })); } // GitHub Provider if (providerConfig.github?.enabled === true) { providers.push(GitHubProvider({ clientId: providerConfig.github?.clientId, clientSecret: providerConfig.github.clientSecret })); } // Credentials Provider if (providerConfig.credentials?.enabled !== false) { const config = providerConfig.credentials; providers.push(CredentialsProvider({ name: 'Credentials', credentials: { email: { label: 'Email', type: 'email' }, password: { label: 'Password', type: 'password' } }, async authorize(credentials) { const { email, password } = credentials; // Validate credentials const isValidCredentials = validateCredentials(email, password); if (!isValidCredentials) { throw new AuthenticationError('Invalid credentials', 'invalid_credentials'); } // Find user and verify password const user = await adapter.getUserByEmail(email); if (!user) { throw new AuthenticationError('User not found', 'user_not_found'); } //if emailverification is required and user email is unverified if (providerConfig.credentials?.requireEmailVerification && !user.emailVerified) { throw new AuthenticationError('Email must be verifued', 'unverified_email'); } // Check account lock status if (user.isLocked && user.lockUntil.getTime() > Date.now()) { throw new AuthenticationError('Account is temporarily locked', 'account_locked'); } const isValidPassword = await verifyPassword(user.password, password); if (!isValidPassword) { // Increment login attempts and potentially lock account handleFailedLoginAttempt(user); throw new AuthenticationError('Invalid email or password', 'invalid_credentials'); } // Prepare user object for session const sessionUser = { id: user.id, email: user.email, name: user.name }; // Add custom fields if specified if (config?.additionalUserFields) { config.additionalUserFields.forEach((field) => { if (user[field] !== undefined) { sessionUser[field] = user[field]; } }); } // Reset login attempts on successful login amd Update last login const updatedData = { id: user.id, isLocked: false, lockUntil: null, lastLoginAt: new Date(), loginAttempts: 0 }; await adapter.updateUser(updatedData); return { ...sessionUser, ...updatedData }; } })); } return providers; // Handle failed login attempts async function handleFailedLoginAttempt(user) { const maxLoginAttempts = securityConfig.maxLoginAttempts || 5; const lockDuration = securityConfig.lockoutDuration || 15 * 60 * 1000; // 15 minutes const updatedUser = await adapter.updateUser({ id: user.id, loginAttempts: user.loginAttempts + 1, isLocked: user.loginAttempts + 1 >= maxLoginAttempts, lockUntil: user.loginAttempts + 1 >= maxLoginAttempts ? new Date(Date.now() + lockDuration) : null }); return updatedUser; } }