@@ -18,6 +18,7 @@ import rateLimit from 'express-rate-limit';
1818import { z } from 'zod' ;
1919import { timingSafeEqual } from 'crypto' ;
2020import cookieParser from 'cookie-parser' ;
21+ import lusca from 'lusca' ;
2122
2223const __filename = fileURLToPath ( import . meta. url ) ;
2324const __dirname = dirname ( __filename ) ;
@@ -71,6 +72,32 @@ app.use(express.urlencoded({ limit: '10mb', extended: true }));
7172app . use ( express . static ( join ( __dirname , '../dist' ) ) ) ;
7273app . use ( cookieParser ( COOKIE_SECRET ) ) ;
7374
75+ // CSRF Protection
76+ app . use ( lusca . csrf ( {
77+ cookie : {
78+ name : '_csrf' ,
79+ secure : process . env . NODE_ENV === 'production' ,
80+ httpOnly : true ,
81+ sameSite : 'strict'
82+ } ,
83+ value : ( req ) => {
84+ // Get CSRF token from header, body, or query string
85+ return req . headers [ 'x-csrf-token' ] ||
86+ req . body && req . body . _csrf ||
87+ req . query && req . query . _csrf ;
88+ }
89+ } ) ) ;
90+
91+ // Add CSRF token to response for SPA
92+ app . use ( ( req , res , next ) => {
93+ res . cookie ( 'XSRF-TOKEN' , req . csrfToken ( ) , {
94+ secure : process . env . NODE_ENV === 'production' ,
95+ sameSite : 'strict' ,
96+ path : '/'
97+ } ) ;
98+ next ( ) ;
99+ } ) ;
100+
74101// Rate limiting
75102const apiLimiter = rateLimit ( {
76103 windowMs : 15 * 60 * 1000 ,
@@ -119,6 +146,19 @@ app.use('/api', apiLimiter);
119146// Initialize database
120147await initializeDatabase ( ) ;
121148
149+ // Add CSRF token endpoint for SPA
150+ app . get ( '/api/csrf-token' , ( req , res ) => {
151+ res . json ( { csrfToken : req . csrfToken ( ) } ) ;
152+ } ) ;
153+
154+ // Apply CSRF protection to all non-GET/HEAD/OPTIONS requests
155+ app . use ( ( req , res , next ) => {
156+ if ( [ 'GET' , 'HEAD' , 'OPTIONS' ] . includes ( req . method ) ) {
157+ return next ( ) ;
158+ }
159+ lusca . csrf ( ) ( req , res , next ) ;
160+ } ) ;
161+
122162// Auth Routes
123163app . get ( '/api/auth/setup-status' , authLimiter , async ( req , res ) => {
124164 try {
0 commit comments