import { ORPCError } from "@orpc/server"; import { adminRoutes } from "./procedures/admin/_routes.js"; import { createLoginRequest as createLoginRequestHandler } from "./procedures/auth/create-login-request.js"; import { forgotPassword as forgotPasswordHandler } from "./procedures/auth/forgot-password.js"; import { loginIfRequestIsCompleted as loginIfRequestIsCompletedHandler } from "./procedures/auth/login-if-completed.js"; import { loginPassword as loginPasswordHandler } from "./procedures/auth/login-password.js"; import { loginPasswordConfirm as loginPasswordConfirmHandler } from "./procedures/auth/login-password-confirm.js"; import { logout as logoutHandler } from "./procedures/auth/logout.js"; import { resendVerificationEmail as resendVerificationHandler } from "./procedures/auth/resend-verification.js"; import { resetPassword as resetPasswordHandler } from "./procedures/auth/reset-password.js"; import { signup as signupHandler } from "./procedures/auth/signup.js"; import { verifyEmail as verifyEmailHandler } from "./procedures/auth/verify-email.js"; import { authMiddleware, loginRequestMiddleware, os, } from "./procedures/base.js"; import { meRoutes } from "./procedures/me/_routes.js"; import { invitesAccept, invitesCancel, invitesCreate, invitesList, membersList, membersRemove, membersUpdateRole, orgsCreate, orgsDelete, orgsGet, orgsLeave, orgsList, orgsUpdate, sitesList, } from "./procedures/orgs/index.js"; import { createAuthenticationOptions as createAuthOptions, createRegistrationOptions as createRegOptions, getRPInfo, verifyAuthentication as verifyAuth, verifyRegistration as verifyReg, } from "./utils/webauthn.js"; // Auth procedures (imported from procedure files) const signup = signupHandler; const verifyEmail = verifyEmailHandler; const resendVerificationEmail = resendVerificationHandler; const createLoginRequest = createLoginRequestHandler; const loginPassword = loginPasswordHandler; const loginPasswordConfirm = loginPasswordConfirmHandler; const loginIfRequestIsCompleted = loginIfRequestIsCompletedHandler; const forgotPassword = forgotPasswordHandler; const resetPassword = resetPasswordHandler; const logout = logoutHandler; // WebAuthn procedures const createRegistrationOptions = os.auth.webauthn.createRegistrationOptions.handler( async ({ input, context }) => { const { email } = input; // Look up existing user by email to exclude their credentials const existingUser = await context.db .selectFrom("users") .select(["id", "display_name"]) .where("email", "=", email) .executeTakeFirst(); const rpInfo = getRPInfo( context.origin, context.allowedOrigins, context.rpName, ); const result = await createRegOptions(context.db, rpInfo, { id: existingUser?.id, email, displayName: existingUser?.display_name, }); return result; }, ); const verifyRegistration = os.auth.webauthn.verifyRegistration .use(authMiddleware) .handler(async ({ input, context }) => { const { challengeId, response } = input; const rpInfo = getRPInfo( context.origin, context.allowedOrigins, context.rpName, ); return verifyReg( context.db, rpInfo, context.user.id, challengeId, response, ); }); const createAuthenticationOptions = os.auth.webauthn.createAuthenticationOptions .use(loginRequestMiddleware) .handler(async ({ context }) => { const rpInfo = getRPInfo( context.origin, context.allowedOrigins, context.rpName, ); const result = await createAuthOptions(context.db, rpInfo, context.user.id); return result; }); const verifyAuthentication = os.auth.webauthn.verifyAuthentication .use(loginRequestMiddleware) .handler(async ({ input, context }) => { const { challengeId, response } = input; const rpInfo = getRPInfo( context.origin, context.allowedOrigins, context.rpName, ); const verified = await verifyAuth( context.db, rpInfo, context.user.id, challengeId, response, ); if (!verified) { throw new ORPCError("BAD_REQUEST", { message: "Authentication failed", }); } // Mark the login request as completed - passkey verification is equivalent to email verification await context.db .updateTable("login_requests") .set({ completed_at: new Date() }) .where("id", "=", String(context.loginRequestId)) .execute(); return { success: true }; }); // Build the router export const router = os.router({ auth: { signup, verifyEmail, resendVerificationEmail, createLoginRequest, loginPassword, loginPasswordConfirm, loginIfRequestIsCompleted, forgotPassword, resetPassword, logout, webauthn: { createRegistrationOptions, verifyRegistration, createAuthenticationOptions, verifyAuthentication, }, }, me: meRoutes, orgs: { list: orgsList, create: orgsCreate, get: orgsGet, update: orgsUpdate, delete: orgsDelete, leave: orgsLeave, members: { list: membersList, updateRole: membersUpdateRole, remove: membersRemove, }, invites: { list: invitesList, create: invitesCreate, cancel: invitesCancel, accept: invitesAccept, }, sites: { list: sitesList, }, }, admin: adminRoutes, });