Add authentication system with session-based auth
Implements full auth flows with opaque tokens (not JWT) for easy revocation: - Login/logout with cookie or bearer token support - Registration with email verification - Password reset with one-time tokens - scrypt password hashing (no external deps) New files in express/auth/: - token.ts: 256-bit token generation, SHA-256 hashing - password.ts: scrypt hashing with timing-safe verification - types.ts: Session schemas, token types, input validation - store.ts: AuthStore interface + InMemoryAuthStore - service.ts: AuthService with all auth operations - routes.ts: 6 auth endpoints Modified: - types.ts: Added user field to Call, requireAuth/requirePermission helpers - app.ts: JSON body parsing, populates call.user, handles auth errors - services.ts: Added services.auth - routes.ts: Includes auth routes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,8 @@ import { routes } from "./routes";
|
||||
import { services } from "./services";
|
||||
// import { URLPattern } from 'node:url';
|
||||
import {
|
||||
AuthenticationRequired,
|
||||
AuthorizationDenied,
|
||||
type Call,
|
||||
type InternalHandler,
|
||||
type Method,
|
||||
@@ -22,6 +24,9 @@ import {
|
||||
|
||||
const app = express();
|
||||
|
||||
// Parse JSON request bodies
|
||||
app.use(express.json());
|
||||
|
||||
services.logging.log({ source: "logging", text: ["1"] });
|
||||
const processedRoutes: { [K in Method]: ProcessedRoute[] } = {
|
||||
GET: [],
|
||||
@@ -52,26 +57,42 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => {
|
||||
}
|
||||
|
||||
console.log("request.originalUrl", request.originalUrl);
|
||||
console.log("beavis");
|
||||
|
||||
// const p = new URL(request.originalUrl);
|
||||
// const path = p.pathname;
|
||||
|
||||
// console.log("p, path", p, path)
|
||||
|
||||
console.log("ok");
|
||||
// Authenticate the request
|
||||
const user = await services.auth.validateRequest(request);
|
||||
|
||||
const req: Call = {
|
||||
pattern: route.path,
|
||||
// path,
|
||||
path: request.originalUrl,
|
||||
method,
|
||||
parameters: { one: 1, two: 2 },
|
||||
request,
|
||||
user,
|
||||
};
|
||||
|
||||
const retval = await route.handler(req);
|
||||
return retval;
|
||||
try {
|
||||
const retval = await route.handler(req);
|
||||
return retval;
|
||||
} catch (error) {
|
||||
// Handle authentication errors
|
||||
if (error instanceof AuthenticationRequired) {
|
||||
return {
|
||||
code: httpCodes.clientErrors.Unauthorized,
|
||||
contentType: contentTypes.application.json,
|
||||
result: JSON.stringify({
|
||||
error: "Authentication required",
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (error instanceof AuthorizationDenied) {
|
||||
return {
|
||||
code: httpCodes.clientErrors.Forbidden,
|
||||
contentType: contentTypes.application.json,
|
||||
result: JSON.stringify({ error: "Access denied" }),
|
||||
};
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
for (const [_idx, method] of methodList.entries()) {
|
||||
|
||||
Reference in New Issue
Block a user