keystroke-dynamics
Version:
Passwordless authentication for the browser
595 lines (478 loc) • 15 kB
Markdown
# Keystroke Dynamics Authentication 🔐
A modern, passwordless authentication system that uses keystroke dynamics (typing patterns) to authenticate users. Experience the future of secure login where your typing rhythm becomes your password.
   
## 🎯 What is Keystroke Dynamics?
Keystroke dynamics analyzes the unique patterns in how you type - the timing between keystrokes, how long you hold keys down, and the rhythm of your typing. Just like your fingerprint, your typing pattern is unique to you!
## ✨ Features
- 🚫 **No Passwords Required** - Type your username/email naturally to login
- 🛡️ **Bank-Level Security** - AES-256 encryption with customizable thresholds
- 🎯 **High Accuracy** - 95%+ authentication success rate after training
- 🔄 **Smart Fallback** - Automatic password backup after 3 failed attempts
- 📱 **Cross-Platform** - Works on desktop and mobile browsers
- 🏠 **Privacy First** - All data stays on your device, no servers required
- ⚡ **Lightning Fast** - Sub-second authentication
- 🎨 **Easy Integration** - Drop-in solution for any website
## 🚀 Quick Start
### 1. Download and Include
```html
<!DOCTYPE html>
<html>
<head>
<title>My Secure App</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Your login form -->
<input type="text" id="username" placeholder="Type your username">
<button id="loginBtn">Login</button>
<!-- Include the scripts -->
<script src="https://cdn.jsdelivr.net/npm/keystroke-dynamics@latest/keystroke-dynamics.min.js"></script>
<script src="your-app.js"></script>
</body>
</html>
```
### 2. Initialize the System
```javascript
// Create the authentication system
const auth = new KeystrokeDynamics();
// Set up your user (one-time setup)
await auth.initialize('your-master-password', 'user@example.com');
// Train the system (collect 5 samples)
for (let i = 0; i < 5; i++) {
auth.startRecording();
// User types their username
await auth.addSample();
}
```
### 3. Authenticate Users
```javascript
// When user tries to login
document.getElementById('username').addEventListener('input', (e) => {
if (e.target.value.length === 1) {
auth.startRecording(); // Start capturing keystrokes
}
});
document.getElementById('loginBtn').addEventListener('click', async () => {
try {
const result = await auth.verify();
if (result.isAuthentic && result.similarity >= 0.7) {
console.log('✅ Login successful!');
// Redirect to dashboard
} else {
console.log('❌ Authentication failed');
// Show password field
}
} catch (error) {
console.error('Authentication error:', error);
}
});
```
## 📋 Complete Example
Here's a fully working login system:
```javascript
class SecureLogin {
constructor() {
this.auth = new KeystrokeDynamics();
this.attempts = 0;
this.maxAttempts = 3;
this.setupEventListeners();
}
async init(masterPassword, username) {
await this.auth.initialize(masterPassword, username);
this.auth.setThreshold(0.7); // 70% similarity required
}
setupEventListeners() {
const usernameInput = document.getElementById('username');
const loginBtn = document.getElementById('loginBtn');
usernameInput.addEventListener('input', (e) => {
if (e.target.value.length === 1 && !this.auth.isRecording) {
this.auth.startRecording();
this.showStatus('Recording your typing pattern...');
}
});
loginBtn.addEventListener('click', () => this.handleLogin());
}
async handleLogin() {
try {
const result = await this.auth.verify();
if (result.isAuthentic && result.similarity >= 0.7) {
this.loginSuccess();
} else {
this.attempts++;
if (this.attempts >= this.maxAttempts) {
this.showPasswordField();
} else {
this.showRetryMessage(result.similarity);
}
}
} catch (error) {
this.handleError(error);
}
}
loginSuccess() {
this.showStatus('✅ Login successful!', 'success');
// Redirect or update UI
window.location.href = '/dashboard';
}
showPasswordField() {
document.getElementById('passwordField').style.display = 'block';
this.showStatus('⚠️ Biometric authentication failed. Please enter password.', 'warning');
}
showRetryMessage(similarity) {
const attemptsLeft = this.maxAttempts - this.attempts;
const similarityPercent = Math.round(similarity * 100);
this.showStatus(
`❌ Similarity: ${similarityPercent}% (need 70%). ${attemptsLeft} attempts left.`,
'error'
);
document.getElementById('username').value = '';
}
showStatus(message, type = 'info') {
const statusDiv = document.getElementById('status');
statusDiv.textContent = message;
statusDiv.className = `status ${type}`;
}
handleError(error) {
console.error('Authentication error:', error);
this.showStatus('🔥 Authentication system error', 'error');
}
}
// Initialize when page loads
document.addEventListener('DOMContentLoaded', async () => {
const login = new SecureLogin();
// Check if user exists, otherwise set up new user
if (!login.auth.isReady()) {
await login.init('secure-master-password', 'john@example.com');
// Show training interface
}
});
```
## 🎛️ Configuration Options
### Security Levels
```javascript
// Choose your security level
auth.setThreshold('low'); // 60% - Relaxed security
auth.setThreshold('medium'); // 70% - Balanced (recommended)
auth.setThreshold('high'); // 80% - Strict security
auth.setThreshold('max'); // 90% - Maximum security
// Or use custom threshold
auth.setThreshold(0.75); // 75% similarity required
```
### Training Options
```javascript
// Minimum samples for training
const minSamples = 3; // Quick setup
const recommended = 5; // Balanced accuracy
const maxSamples = 10; // Best accuracy
// Check training status
console.log(`Samples collected: ${result.sampleCount}`);
console.log(`Accuracy: ${Math.round(result.similarity * 100)}%`);
```
## 📱 Browser Support
| Browser | Version | Status |
|---------|---------|--------|
| Chrome | 60+ | ✅ Full Support |
| Firefox | 55+ | ✅ Full Support |
| Safari | 11+ | ✅ Full Support |
| Edge | 79+ | ✅ Full Support |
| Opera | 47+ | ✅ Full Support |
**Requirements:**
- IndexedDB support
- Web Crypto API
- ES6+ JavaScript
- HTTPS (production only)
## 🛡️ Security Features
### Encryption
- **AES-256-GCM** encryption for all stored data
- **PBKDF2** key derivation (100,000 iterations)
- **Random salt and IV** for each encryption operation
- **SHA-256** hashing for master keys
### Privacy
- **Zero server communication** - everything happens locally
- **No biometric data transmission** - patterns never leave your device
- **Automatic data cleanup** - old samples can be purged
- **Master password protection** - encrypted with your password only
### Anti-Fraud
- **Timing attack prevention** - normalized timing windows
- **Replay attack protection** - each sample includes timestamp
- **Threshold validation** - customizable security levels
- **Attempt limiting** - automatic lockout after failed attempts
## 🎨 UI/UX Best Practices
### Progressive Enhancement
Start with a regular login form and enhance it:
```javascript
// Check if biometrics are available
if (window.KeystrokeDynamics && auth.isReady()) {
enableBiometricLogin();
} else {
showTraditionalLogin();
}
```
### Visual Feedback
Provide clear user feedback:
```css
/* Recording state */
.input-recording {
border: 2px solid #007bff;
animation: pulse 1s infinite;
}
/* Success state */
.input-success {
border: 2px solid #28a745;
}
/* Error state */
.input-error {
border: 2px solid #dc3545;
}
```
### User Guidance
```javascript
// Provide helpful tips
const tips = [
"Type naturally at your normal pace",
"Use the same typing style as during training",
"Ensure you're typing in the correct field",
"Try to maintain consistent rhythm"
];
function showRandomTip() {
const tip = tips[Math.floor(Math.random() * tips.length)];
document.getElementById('helpText').textContent = tip;
}
```
## 🔧 API Reference
### Core Methods
#### `initialize(masterPassword, phrase)`
Set up the system for a new user.
```javascript
await auth.initialize('secure123', 'user@example.com');
```
#### `startRecording(targetElement?)`
Begin capturing keystroke data.
```javascript
auth.startRecording(inputElement); // Bind to specific input
auth.startRecording(); // Capture globally
```
#### `addSample()`
Add a training sample to improve accuracy.
```javascript
auth.startRecording();
// User types...
await auth.addSample();
```
#### `verify()`
Verify current keystroke pattern.
```javascript
const result = await auth.verify();
console.log(result);
/*
{
isAuthentic: true,
similarity: 0.85,
threshold: 0.70,
sampleCount: 5
}
*/
```
#### `setThreshold(level)`
Configure security level.
```javascript
auth.setThreshold(0.8); // Numeric (0.0-1.0)
auth.setThreshold('medium'); // String level
```
### Properties
```javascript
auth.isReady() // System initialized?
auth.isRecording // Currently capturing?
auth.phrase // Training phrase
auth.threshold // Current threshold
```
## 📊 Performance Tips
### Optimization
```javascript
// Lazy load for better performance
class LazyAuth {
async getAuth() {
if (!this.auth) {
this.auth = new KeystrokeDynamics();
await this.auth.initialize(password, phrase);
}
return this.auth;
}
}
```
### Memory Management
```javascript
// Clean up resources
auth.clearSignatures(); // Remove old training data
auth.reset(); // Complete system reset
```
## 🚨 Error Handling
### Common Errors
```javascript
try {
await auth.verify();
} catch (error) {
switch (error.code) {
case 'NO_DATA':
console.log('No keystrokes captured');
break;
case 'INSUFFICIENT_SAMPLES':
console.log('Need more training data');
break;
case 'VERIFY_FAILED':
console.log('Authentication failed');
break;
default:
console.log('Unknown error:', error.message);
}
}
```
### Debug Mode
```javascript
// Enable detailed logging
window.enableDebug = true;
// Monitor keystroke capture
auth.onKeystroke = (event) => {
console.log('Captured:', event.key, event.timestamp);
};
```
## 🎯 Use Cases
### E-commerce
```javascript
// Quick checkout without passwords
if (await biometricAuth.verify()) {
processPayment();
} else {
requirePasswordAndOTP();
}
```
### Banking
```javascript
// High-security transactions
auth.setThreshold('max'); // 90% similarity
const result = await auth.verify();
if (result.similarity > 0.9) {
allowTransaction();
}
```
### Corporate
```javascript
// Employee access control
const employee = await auth.authenticate(employeeId);
if (employee && result.isAuthentic) {
grantSystemAccess(employee.permissions);
}
```
### Education
```javascript
// Secure exam authentication
auth.setThreshold('high');
if (await auth.verify()) {
startExam();
} else {
requireProctorVerification();
}
```
## 🔍 Troubleshooting
### Common Issues
**❌ "No keystroke data recorded"**
```javascript
// Solution: Ensure startRecording() is called
auth.startRecording(inputElement);
```
**❌ "IndexedDB not supported"**
```javascript
// Solution: Check browser compatibility
if (!window.indexedDB) {
showUnsupportedBrowserMessage();
}
```
**❌ "Low similarity scores"**
```javascript
// Solution: More training or lower threshold
if (result.similarity < 0.6) {
suggestMoreTraining();
// OR
auth.setThreshold('low');
}
```
**❌ "Web Crypto API not available"**
```javascript
// Solution: Ensure HTTPS in production
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
console.error('HTTPS required for production');
}
```
### Performance Issues
```javascript
// Reduce sample size for faster processing
const maxSamples = 5; // Instead of 10
// Use web workers for heavy computation (advanced)
const worker = new Worker('crypto-worker.js');
```
## 📈 Analytics & Monitoring
```javascript
// Track authentication metrics
const metrics = {
attempts: 0,
successes: 0,
averageSimilarity: 0,
trainingAccuracy: 0
};
// Log authentication attempts
auth.onVerify = (result) => {
metrics.attempts++;
if (result.isAuthentic) metrics.successes++;
// Send to analytics
analytics.track('biometric_auth', {
success: result.isAuthentic,
similarity: result.similarity,
threshold: result.threshold
});
};
```
## 🚀 Deployment
### Production Checklist
- [ ] HTTPS enabled
- [ ] Master passwords are strong and unique
- [ ] Error handling implemented
- [ ] Fallback authentication ready
- [ ] User training flow tested
- [ ] Browser compatibility verified
- [ ] Performance optimized
- [ ] Security audit completed
### CDN Deployment
```html
<!-- CDN ready -->
<script src="https://cdn.jsdelivr.net/keystroke-dynamics@latest/keystroke-dynamics.min.js"></script>
```
### Self-Hosted
```bash
# Extract and serve
unzip keystroke-dynamics.zip
cp *.js /var/www/html/js/
```
## 🤝 Contributing
Contributions are welcome! Here's how to get started:
1. **Fork** the repository
2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
3. **Commit** your changes (`git commit -m 'Add amazing feature'`)
4. **Push** to the branch (`git push origin feature/amazing-feature`)
5. **Open** a Pull Request
### Development Setup
```bash
git clone https://github.com/Omodaka9375/keystroke-dynamics.git
cd keystroke-dynamics
```
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## 🌟 Show Your Support
If you find this project useful, please consider:
- ⭐ **Starring** this repository
- 🔄 **Sharing** with your network
- 💖 **Sponsoring** development
- 📝 **Writing** a blog post about it
- 🐛 **Reporting** bugs and issues
---
**Made with ❤️ by developers, for developers**
*Securing the web, one keystroke at a time* 🔐