Framework-agnostic CSRF protection core functionality
npm install @csrf-armor/core





Framework-agnostic CSRF protection with multiple security strategies and zero dependencies.
Built for modern web applications that need flexible, high-performance CSRF protection without vendor lock-in.
``bash`
npm install @csrf-armor/core
`typescript
import { generateSignedToken, parseSignedToken } from '@csrf-armor/core';
// Generate a secure token
const token = await generateSignedToken('your-32-char-secret', 3600);
// Validate the token later
const payload = await parseSignedToken(submittedToken, 'your-32-char-secret');
console.log('Token valid until:', new Date(payload.exp * 1000));
`
> ⚠️ SECURITY WARNING: Use a strong secret in production! Generate with crypto.getRandomValues(new Uint8Array(32)).
---
| Strategy | Security | Performance | Best For | Setup Complexity |
|----------|----------|-------------|----------|------------------|
| Signed Double Submit ⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | E-commerce, finance | Medium |
| Double Submit | ⭐ | ⭐⭐⭐⭐⭐ | Local development | Easy |
| Signed Token | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | APIs, microservices | Medium |
| Origin Check | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | Mobile backends | Easy |
| Hybrid | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | Maximum security | Hard |
---
> 💡 Complete Express.js solution: @csrf-armor/express with React hooks and simplified setup.
> 💡 Complete Next.js solution: @csrf-armor/nextjs with React hooks and simplified setup.
🔌 More framework examples and adapters: Advanced Configuration Guide →
---
`typescript
import { createCsrfProtection } from '@csrf-armor/core';
// Recommended for most applications
const csrfProtection = createCsrfProtection(adapter, {
strategy: 'signed-double-submit',
secret: process.env.CSRF_SECRET!, // ⚠️ Required in production
cookie: {
secure: true, // HTTPS only
sameSite: 'strict' // Strict same-site policy
}
});
`
`typescript
// High Security (Financial, Healthcare)
{ strategy: 'hybrid', secret: process.env.CSRF_SECRET!, allowedOrigins: ['https://app.com'] }
// High Performance (Public APIs)
{ strategy: 'origin-check', allowedOrigins: ['https://mobile.app'] }
// Balanced (Most Web Apps)
{ strategy: 'signed-double-submit', secret: process.env.CSRF_SECRET! }
// Development
{ strategy: 'double-submit', cookie: { secure: false } }
`
📚 Complete configuration options: Advanced Configuration Guide →
---
`typescript
// Ensure your adapter extracts tokens from all sources
async getTokenFromRequest(request: CsrfRequest, config: RequiredCsrfConfig) {
const headers = request.headers instanceof Map
? request.headers
: new Map(Object.entries(request.headers));
// Try header first
const headerValue = headers.get(config.token.headerName.toLowerCase());
if (headerValue) return headerValue;
// Try form data
if (request.body && typeof request.body === 'object') {
const body = request.body as Record
const formValue = body[config.token.fieldName];
if (typeof formValue === 'string') return formValue;
}
return undefined;
}
`
`typescript`
const config = {
cookie: {
domain: '.yourdomain.com', // Note the leading dot
sameSite: 'lax' // 'strict' blocks cross-subdomain
}
};
`typescript`
const config = {
excludePaths: ['/api/webhooks', '/api/public', '/health'],
skipContentTypes: ['application/json'] // For JSON-only APIs
};
Choose a faster strategy or exclude read-only endpoints:
`typescript
// Option 1: Faster strategy
{ strategy: 'double-submit' } // No crypto overhead
// Option 2: Exclude read-only paths
{ excludePaths: ['/api/read', '/api/search'] }
`
---
`typescript
// Generate signed tokens
const token = await generateSignedToken('secret', 3600);
// Parse and validate
const payload = await parseSignedToken(token, 'secret');
console.log('Expires:', new Date(payload.exp * 1000));
// Generate random nonces
const nonce = generateNonce(32); // 64 hex characters
`
`typescript
const protection = createCsrfProtection(adapter, config);
const result = await protection.protect(request, response);
if (result.success) {
console.log('CSRF token:', result.token);
} else {
console.error('Validation failed:', result.reason);
}
`
`typescript
import { TokenExpiredError, TokenInvalidError, OriginMismatchError } from '@csrf-armor/core';
try {
await parseSignedToken(token, secret);
} catch (error) {
if (error instanceof TokenExpiredError) {
// Handle expired token
} else if (error instanceof TokenInvalidError) {
// Handle invalid signature
}
}
`
📖 Complete API documentation: Advanced Configuration Guide →
---
- Advanced Configuration Guide - Complex setups, custom strategies, all config options
- Security Analysis - Security model deep-dive and best practices
- Migration Guide - How to migrate from existing CSRF libraries
---
Community contributions welcome! This project would benefit from:
🎯 High-Impact Contributions:
- Framework adapters: Express, Fastify, Koa, SvelteKit, Remix
- Performance optimizations: Benchmark improvements, edge cases
- Security enhancements: Vulnerability reports, new strategies
- Developer experience: Better examples, TypeScript improvements
🚀 Getting Started:
1. Fork the repository
2. Create a feature branch: git checkout -b feature/express-adapter`
3. Make your changes with tests
4. Submit a PR with clear description
💬 Get Help:
- 🐛 Report bugs
- 💡 Request features
- 💬 Ask questions
---
- @csrf-armor/nextjs - Next.js App Router middleware and React hooks
- @csrf-armor/express - Express.js middleware adapter
More framework packages coming based on community demand and contributions!
---
MIT © Muneeb Samuels
Questions? Open an issue or start a discussion!