When trying to post a job, users were getting a CSRF (Cross-Site Request Forgery) failure error:
Error[object Object]WARN: Security event: csrf_failure
POST /api/recruiter/jobs 400 in 109ms
This happened because:
- The API endpoints require CSRF protection (
requireCSRF: true) - The client-side forms were not sending the required CSRF token in request headers
- The security middleware was rejecting requests without proper CSRF tokens
Created a comprehensive CSRF token management system:
useCSRFToken()hook that generates and manages CSRF tokenssecureApiRequest()utility function that automatically includes CSRF tokens in API requests- Tokens are stored as cookies and included in
x-csrf-tokenheaders
Updated all components that make POST/PUT/DELETE API requests:
src/app/recruiter/jobs/page.tsx- Main job management pagesrc/app/recruiter/_modules/job-posting-form.tsx- Detailed job posting formsrc/app/recruiter/post-job/_modules/simple-job-posting-form.tsx- Simple job posting formsrc/app/recruiter/post/_modules/job-posting-form.tsx- Alternative job posting form
src/app/recruiter/profile/page.tsx- Recruiter profile CRUD operations
src/app/recruiter/_modules/candidate-list.tsx- Interview scheduling and candidate refresh
- When a component mounts,
useCSRFToken()generates a random 32-character token - The token is stored as a
csrf-tokencookie - When making API requests,
secureApiRequest()automatically:- Reads the token from the cookie
- Includes it in the
x-csrf-tokenheader - Sets proper
Content-Type: application/jsonheader
- Tokens are generated client-side using cryptographically secure random strings
- Tokens are validated server-side by comparing header and cookie values
- Only state-changing operations (POST/PUT/DELETE) require CSRF tokens
- Tokens are scoped to the current session
Created a test page at /test-csrf to verify the CSRF token functionality works correctly.
src/hooks/use-csrf-token.ts(new)src/app/test-csrf/page.tsx(new)src/app/recruiter/jobs/page.tsxsrc/app/recruiter/profile/page.tsxsrc/app/recruiter/_modules/candidate-list.tsxsrc/app/recruiter/post-job/_modules/simple-job-posting-form.tsxsrc/app/recruiter/post/_modules/job-posting-form.tsx
✅ Job posting now works without CSRF failures ✅ All recruiter API operations are properly protected ✅ Security is maintained while providing smooth user experience ✅ Consistent CSRF handling across the entire application
To use in new components:
import { useCSRFToken, secureApiRequest } from '~/hooks/use-csrf-token';
function MyComponent() {
const csrfToken = useCSRFToken();
const handleSubmit = async (data) => {
const response = await secureApiRequest('/api/endpoint', {
method: 'POST',
body: JSON.stringify(data),
});
// Handle response...
};
}