Implement auth procedures with code review fixes
Add complete auth backend (Workstream D): - Auth middleware for session/API key authentication - Signup with password or passkey (WebAuthn) - Login flow with device trust and email confirmation - Password reset and email verification - Session management and logout Utilities created: - cookies.ts: Cookie helpers and configuration - crypto.ts: Token generation and hashing - password.ts: zxcvbn validation, argon2id hashing - geo.ts: IP/location extraction from headers - email.ts: Stubbed email sending - session.ts: Session creation and device trust Code review improvements applied: - Use ORPCError instead of Error in procedures - Add ast-grep rule to enforce ORPCError usage - Remove error info leakage (generic messages) - Optimize N+1 query with JOIN in login-password - Extract signupWithPassword/signupWithPasskey for testability - Add 15-minute WebAuthn challenge expiry check - Strengthen CookieOptions type definitions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,18 @@ import type {
|
||||
AuthenticatedContext,
|
||||
LoginRequestContext,
|
||||
} from "./context.js";
|
||||
import { implement } from "@orpc/server";
|
||||
import { implement, ORPCError } from "@orpc/server";
|
||||
import { contract } from "@reviq/api-contract";
|
||||
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 {
|
||||
createAuthenticationOptions as createAuthOptions,
|
||||
createRegistrationOptions as createRegOptions,
|
||||
@@ -17,49 +27,25 @@ import {
|
||||
const os = implement(contract);
|
||||
|
||||
// Auth procedures
|
||||
const signup = os.auth.signup.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const signup = signupHandler;
|
||||
|
||||
const verifyEmail = os.auth.verifyEmail.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const verifyEmail = verifyEmailHandler;
|
||||
|
||||
const resendVerificationEmail = os.auth.resendVerificationEmail.handler(
|
||||
async () => {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
);
|
||||
const resendVerificationEmail = resendVerificationHandler;
|
||||
|
||||
const createLoginRequest = os.auth.createLoginRequest.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const createLoginRequest = createLoginRequestHandler;
|
||||
|
||||
const loginPassword = os.auth.loginPassword.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const loginPassword = loginPasswordHandler;
|
||||
|
||||
const loginPasswordConfirm = os.auth.loginPasswordConfirm.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const loginPasswordConfirm = loginPasswordConfirmHandler;
|
||||
|
||||
const loginIfRequestIsCompleted = os.auth.loginIfRequestIsCompleted.handler(
|
||||
async () => {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
);
|
||||
const loginIfRequestIsCompleted = loginIfRequestIsCompletedHandler;
|
||||
|
||||
const forgotPassword = os.auth.forgotPassword.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const forgotPassword = forgotPasswordHandler;
|
||||
|
||||
const resetPassword = os.auth.resetPassword.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const resetPassword = resetPasswordHandler;
|
||||
|
||||
const logout = os.auth.logout.handler(async () => {
|
||||
throw new Error("Not implemented");
|
||||
});
|
||||
const logout = logoutHandler;
|
||||
|
||||
// WebAuthn procedures
|
||||
const createRegistrationOptions =
|
||||
@@ -111,7 +97,9 @@ const verifyAuthentication = os.auth.webauthn.verifyAuthentication.handler(
|
||||
);
|
||||
|
||||
if (!verified) {
|
||||
throw new Error("Authentication failed");
|
||||
throw new ORPCError("BAD_REQUEST", {
|
||||
message: "Authentication failed",
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user