Security Middleware
CSRF Protection
Protect your application against Cross-Site Request Forgery (CSRF) attacks with built-in token validation and secure cookie handling.
Basic CSRF Protection
MoroJS provides built-in CSRF protection middleware that automatically validates CSRF tokens for state-changing requests.
Enable CSRF Protectiontypescript
1import { middleware } from '@morojs/moro';
2
3// Enable CSRF protection globally
4app.use(middleware.csrf({
5 cookie: {
6 name: '_csrf',
7 httpOnly: true,
8 secure: process.env.NODE_ENV === 'production',
9 sameSite: 'strict'
10 },
11 ignoreMethods: ['GET', 'HEAD', 'OPTIONS'],
12 headerName: 'X-CSRF-Token'
13}));
14
15// Get CSRF token endpoint
16app.get('/api/csrf-token', (req, res) => {
17 return { csrfToken: req.csrfToken() };
18});
19
20// Protected endpoint
21app.post('/api/transfer')
22 .csrf() // Validate CSRF token
23 .handler((req, res) => {
24 // Process transfer - token already validated
25 return { success: true };
26 });How CSRF Protection Works
- Generates a unique CSRF token for each session
- Stores token in secure, httpOnly cookie
- Validates token on state-changing requests (POST, PUT, DELETE, PATCH)
- Ignores safe methods (GET, HEAD, OPTIONS)
- Returns 403 Forbidden if token is missing or invalid
Advanced Configuration
Custom CSRF Configurationtypescript
1import { middleware } from '@morojs/moro';
2
3// Advanced CSRF configuration
4app.use(middleware.csrf({
5 cookie: {
6 name: '_csrf',
7 httpOnly: true,
8 secure: process.env.NODE_ENV === 'production',
9 sameSite: 'strict',
10 maxAge: 24 * 60 * 60 * 1000 // 24 hours
11 },
12 ignoreMethods: ['GET', 'HEAD', 'OPTIONS'],
13 headerName: 'X-CSRF-Token',
14 skip: (req) => {
15 // Skip CSRF for API endpoints with API key authentication
16 return req.headers['x-api-key'] !== undefined;
17 }
18}));
19
20// Per-route CSRF configuration
21app.post('/api/sensitive-action')
22 .csrf({
23 cookie: {
24 name: '_csrf',
25 httpOnly: true,
26 secure: true
27 }
28 })
29 .handler((req, res) => {
30 return { success: true };
31 });Client-Side Integration
Fetching and Using CSRF Tokentypescript
1// Fetch CSRF token from server
2async function getCsrfToken() {
3 const response = await fetch('/api/csrf-token');
4 const { csrfToken } = await response.json();
5 return csrfToken;
6}
7
8// Use CSRF token in requests
9async function makeProtectedRequest(data) {
10 const csrfToken = await getCsrfToken();
11
12 const response = await fetch('/api/transfer', {
13 method: 'POST',
14 headers: {
15 'Content-Type': 'application/json',
16 'X-CSRF-Token': csrfToken
17 },
18 credentials: 'include', // Include cookies
19 body: JSON.stringify(data)
20 });
21
22 return response.json();
23}
24
25// React example
26function TransferForm() {
27 const [csrfToken, setCsrfToken] = useState('');
28
29 useEffect(() => {
30 fetch('/api/csrf-token')
31 .then(res => res.json())
32 .then(data => setCsrfToken(data.csrfToken));
33 }, []);
34
35 const handleSubmit = async (e) => {
36 e.preventDefault();
37
38 await fetch('/api/transfer', {
39 method: 'POST',
40 headers: {
41 'Content-Type': 'application/json',
42 'X-CSRF-Token': csrfToken
43 },
44 credentials: 'include',
45 body: JSON.stringify(formData)
46 });
47 };
48
49 return (
50 <form onSubmit={handleSubmit}>
51 <input type="hidden" name="_csrf" value={csrfToken} />
52 {/* form fields */}
53 </form>
54 );
55}Best Practices
Do
- Enable CSRF for all state-changing requests
- Use httpOnly cookies for token storage
- Set secure flag in production
- Use sameSite: 'strict' for maximum security
- Validate token on server-side
- Regenerate token after use for sensitive operations
Don't
- Disable CSRF for state-changing requests
- Store CSRF token in localStorage or sessionStorage
- Skip CSRF validation for sensitive endpoints
- Use predictable or static tokens
- Trust client-side validation only
- Expose CSRF token in error messages