UNPKG

@auth/core

Version:

Authentication for the Web.

85 lines (84 loc) 2.94 kB
import { createHash, randomString, toRequest } from "../../utils/web.js"; import { AccessDenied } from "../../../errors.js"; /** * Starts an e-mail login flow, by generating a token, * and sending it to the user's e-mail (with the help of a DB adapter). * At the end, it returns a redirect to the `verify-request` page. */ export async function sendToken(request, options) { const { body } = request; const { provider, callbacks, adapter } = options; const normalizer = provider.normalizeIdentifier ?? defaultNormalizer; const email = normalizer(body?.email); const defaultUser = { id: crypto.randomUUID(), email, emailVerified: null }; const user = (await adapter.getUserByEmail(email)) ?? defaultUser; const account = { providerAccountId: email, userId: user.id, type: "email", provider: provider.id, }; let authorized; try { authorized = await callbacks.signIn({ user, account, email: { verificationRequest: true }, }); } catch (e) { throw new AccessDenied(e); } if (!authorized) throw new AccessDenied("AccessDenied"); if (typeof authorized === "string") { return { redirect: await callbacks.redirect({ url: authorized, baseUrl: options.url.origin, }), }; } const { callbackUrl, theme } = options; const token = (await provider.generateVerificationToken?.()) ?? randomString(32); const ONE_DAY_IN_SECONDS = 86400; const expires = new Date(Date.now() + (provider.maxAge ?? ONE_DAY_IN_SECONDS) * 1000); const secret = provider.secret ?? options.secret; const baseUrl = new URL(options.basePath, options.url.origin); const sendRequest = provider.sendVerificationRequest({ identifier: email, token, expires, url: `${baseUrl}/callback/${provider.id}?${new URLSearchParams({ callbackUrl, token, email, })}`, provider, theme, request: toRequest(request), }); const createToken = adapter.createVerificationToken?.({ identifier: email, token: await createHash(`${token}${secret}`), expires, }); await Promise.all([sendRequest, createToken]); return { redirect: `${baseUrl}/verify-request?${new URLSearchParams({ provider: provider.id, type: provider.type, })}`, }; } function defaultNormalizer(email) { if (!email) throw new Error("Missing email from request body."); // Get the first two elements only, // separated by `@` from user input. let [local, domain] = email.toLowerCase().trim().split("@"); // The part before "@" can contain a "," // but we remove it on the domain part domain = domain.split(",")[0]; return `${local}@${domain}`; }