Documentation
Everything you need to integrate Inslash into your application
1. Get Your Credentials
Before using Inslash, you need an API key to access our secure hashing infrastructure.
- Sign Up: Create an account at inslash-q5s6.vercel.app/
- Get API Key: Navigate to the API Keys section in your dashboard.
- Save It: Copy the key
(starts with
sk_) - you'll need it for the next step.
2. Choose Integration
Option A: Node.js Library (Recommended)
Best for Node.js applications. Provides type safety, automatic fallback, and utility helpers.
Installation
Usage
const inslash = require('inslash');
// Configuration
inslash.configure({
apiKey: 'sk_test_51Mz...',
apiUrl: 'https://inslash-q5s6.vercel.app/'
});
const { hash } = inslash;
async function example() {
// Hash password (using API with local fallback)
const { passport } = await hash('password123', 'your-pepper-secret');
// Store passport in DB
console.log(passport);
}
Features
🔐 Multiple Algorithms
Support for SHA-256, SHA-384, and SHA-512 HMAC algorithms
🎫 Passport Encoding
All metadata encoded in a single string for easy storage
⚡ Automatic Upgrades
Detects when hashes need upgrading to stronger algorithms
🛡️ Timing-Safe
Protection against timing attacks with constant-time comparison
Migration Guide
Moving from legacy hashing (like bcrypt or manual PBKDF2) to Inslash is designed to be zero-downtime.
The "Lazy Migration" Strategy
You don't need to re-hash your entire database at once. Instead, upgrade users when they next log in.
async function login(email, password) {
const user = await db.findUser(email);
// 1. Check if user is already using Inslash
if (user.password_hash.startsWith('$inslash$')) {
const { valid, needsUpgrade, upgradedPassport } = await inslash.verify(password, user.password_hash, secret);
if (!valid) return false;
if (needsUpgrade) {
await user.update({ password_hash: upgradedPassport });
}
} else {
// 2. Legacy check (e.g. bcrypt)
const isLegacyValid = await bcrypt.compare(password, user.password_hash);
if (!isLegacyValid) return false;
// 3. Transparently migrate to Inslash
const { passport } = await inslash.hash(password, secret);
await user.update({ password_hash: passport });
}
return true;
}
1. Update Schema
Ensure your password column can hold ~128-256 chars (Passports are longer than bcrypt).
2. Standardize Pepper
Pick a consistent secret key (pepper) to use for all new Inslash hashes.
3. Deploy & Profit
Watch your database legacy hashes disappear as users log back in.
hash(value, secret, options)
Creates a secure hash of a password.
| Parameter | Type | Required | Description |
|---|---|---|---|
| value | string |
Required | The password to hash |
| secret | string |
Required | Secret key (pepper) for additional security |
| options | object |
Optional | Configuration options |
Options
| Parameter | Type | Required | Description |
|---|---|---|---|
| algorithm | string |
Optional | Hash algorithm: "sha256", "sha384", or "sha512" (default: "sha256") |
| iterations | number |
Optional | Number of iterations (default: 100,000) |
| saltLength | number |
Optional | Length of salt in bytes (default: 16) |
| hashLength | number |
Optional | Length of hash in bytes (default: 32) |
Returns
Object containing:
passport- Encoded string to store in databasehash- The raw hash valuesalt- The generated saltmetadata- Algorithm, iterations, etc.
verify(value, passport, secret, options)
Verifies a password against a stored passport.
| Parameter | Type | Required | Description |
|---|---|---|---|
| value | string |
Required | The password to verify |
| passport | string |
Required | The stored passport from hash() |
| secret | string |
Required | Same secret key used for hashing |
| options | object |
Optional | Upgrade configuration |
Returns
Object containing:
valid- Boolean indicating if password is correctneedsUpgrade- Boolean indicating if hash should be upgradedupgradedPassport- New passport if upgrade neededmetadata- Current hash metadata
Security Presets
v2.0Use named presets instead of tuning options manually. Presets map to battle-tested option sets.
| Preset | Algorithm | Iterations | Salt | Hash | Use Case |
|---|---|---|---|---|---|
| fast | sha256 | 50,000 | 16 | 32 | Dev / low-stakes |
| balanced | sha256 | 100,000 | 16 | 32 | Default / general use |
| strong ★ | sha384 | 200,000 | 24 | 48 | Recommended for production |
| paranoid | sha512 | 400,000 | 32 | 64 | High-security / financial |
const { hash, SECURITY_PRESETS } = require('inslash');
// Use a named preset
const result = await hash('myPassword', secret, { preset: 'strong' });
// Or access preset values directly
console.log(SECURITY_PRESETS.paranoid);
// { iterations: 400000, saltLength: 32, hashLength: 64, algorithm: 'sha512' }
batchVerify(values, passport, secret, options?)
v2.0Verify multiple values against the same passport. Runs with concurrency control to avoid CPU starvation.
| Parameter | Type | Required | Description |
|---|---|---|---|
| values | string[] |
Required | Array of values to verify (max 50 per API call) |
| passport | string |
Required | The stored passport from hash() |
| secret | string |
Required | Same secret key used for hashing |
| options.concurrency | number |
Optional | Max parallel verifications (default: 4) |
Returns
Array of result objects, each containing:
value— the input valuevalid— booleanneedsUpgrade— booleanerror— string (if that value failed)
const { batchVerify } = require('inslash');
const results = await batchVerify(
['guess1', 'guess2', 'correctPassword'],
storedPassport,
secret,
{ concurrency: 4 }
);
// [{ value: 'guess1', valid: false }, { value: 'correctPassword', valid: true, needsUpgrade: false }]
inspectPassport(passport)
v2.0Decode a passport and read its metadata without verifying. Useful for auditing, debugging, and admin tooling.
| Parameter | Type | Required | Description |
|---|---|---|---|
| passport | string |
Required | The passport string to inspect |
Returns
valid— boolean (false if passport is malformed)version, algorithm, iterations, saltLength, hashLength, encodinghistory— full upgrade audit trail
const { inspectPassport } = require('inslash');
const info = inspectPassport(storedPassport);
console.log(info.algorithm); // 'sha384'
console.log(info.iterations); // 200000
console.log(info.history); // [{ date, algorithm, event }]
comparePassports(passport1, passport2)
v2.0Structurally compare two passports. Does not verify plaintext — only compares encoded metadata and hash values.
Returns
sameAlgorithm, sameIterations, sameEncoding, sameSalt, sameHash— booleansidentical— true when both hash AND salt match (same passport)
const { comparePassports } = require('inslash');
const cmp = comparePassports(passportA, passportB);
console.log(cmp.sameAlgorithm); // true
console.log(cmp.identical); // false (different salts)
estimateSecurity(passport)
v2.0Score a passport's security strength (0–100) and get actionable recommendations.
Scoring Methodology
Returns
score— 0–100level— Excellent / Strong / Good / Fair / Weak / Critical / Invalidrecommendations— string[] of actionable improvementsmetadata— algorithm, iterations, saltLength, hashLength
const { estimateSecurity } = require('inslash');
const { score, level, recommendations } = estimateSecurity(storedPassport);
console.log(score); // 78
console.log(level); // 'Strong'
console.log(recommendations); // ['Consider upgrading to sha512']
generateApiKey(options?)
v2.0Generate a cryptographically secure API key. Useful for generating tokens, secrets, or session keys.
| Parameter | Type | Required | Description |
|---|---|---|---|
| prefix | string |
Optional | Key prefix (default: "inslash") |
| byteLength | number |
Optional | Random bytes to generate (default: 32) |
| encoding | string |
Optional | "hex" | "base64" | "base64url" (default: "hex") |
const { generateApiKey } = require('inslash');
const key = generateApiKey({ prefix: 'myapp', byteLength: 32 });
console.log(key); // 'myapp_a3f9b2c1...'
deriveKey(password, salt, opts?)
v2.0Derive a deterministic encryption key from a password using PBKDF2. Use this for symmetric encryption key derivation, not authentication.
Note: Use hash() for
password authentication. Use deriveKey() only when you need a deterministic key for encryption
(e.g. AES-256).
| Parameter | Type | Required | Description |
|---|---|---|---|
| password | string |
Required | The password to derive from |
| salt | string |
Required | Hex salt string |
| opts.iterations | number |
Optional | PBKDF2 iterations (default: 200,000) |
| opts.keyLength | number |
Optional | Output key length in bytes (default: 32) |
| opts.algorithm | string |
Optional | sha256 | sha384 | sha512 (default: sha512) |
Returns
Promise<Buffer> — the derived
key as a Node.js Buffer.
const { deriveKey } = require('inslash');
const crypto = require('crypto');
const salt = crypto.randomBytes(16).toString('hex');
const keyBuffer = await deriveKey('userPassword', salt, {
iterations: 200_000,
keyLength: 32, // 256-bit AES key
algorithm: 'sha512'
});
// Use keyBuffer with AES-256-GCM for encryption
Example: Complete Authentication System
Full Express.js authentication with login, automatic upgrades, and session management:
const express = require('express');
const session = require('express-session');
const { hash, verify } = require('inslash');
const User = require('./models/User');
const app = express();
app.use(express.json());
app.use(session({
secret: 'your-session-secret',
resave: false,
saveUninitialized: false
}));
// Login endpoint
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify password
const result = await verify(password, user.passport, process.env.HASH_PEPPER);
if (!result.valid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Automatic security upgrade
if (result.needsUpgrade) {
user.passport = result.upgradedPassport;
await user.save();
console.log('Password hash upgraded for user:', user.email);
}
// Create session
req.session.userId = user._id;
res.json({ success: true, user: { id: user._id, email: user.email } });
});
// Protected route middleware
function requireAuth(req, res, next) {
if (!req.session.userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}
app.get('/dashboard', requireAuth, (req, res) => {
res.json({ message: 'Welcome to your dashboard!' });
});
app.listen(3000);
Example: User Registration Flow
Complete user registration with validation and secure password storage:
const { hash } = require('inslash');
const User = require('./models/User');
app.post('/signup', async (req, res) => {
const { username, email, password, confirmPassword } = req.body;
// Validation
if (!username || !email || !password) {
return res.status(400).json({ error: 'All fields required' });
}
if (password !== confirmPassword) {
return res.status(400).json({ error: 'Passwords do not match' });
}
if (password.length < 8) {
return res.status(400).json({ error: 'Password must be at least 8 characters' });
}
// Check if user exists
const existingUser = await User.findOne({ $or: [{ username }, { email }] });
if (existingUser) {
return res.status(400).json({ error: 'Username or email already exists' });
}
// Hash password with strong settings
const hashResult = await hash(password, process.env.HASH_PEPPER, {
algorithm: 'sha512',
iterations: 150000
});
// Create user
const user = new User({
username,
email,
passport: hashResult.passport,
createdAt: new Date()
});
await user.save();
// Auto-login after registration
req.session.userId = user._id;
res.status(201).json({ success: true, user: { id: user._id, username: user.username, email: user.email } });
});
Example: Password Reset System
Secure password reset with email tokens:
const crypto = require('crypto');
const { hash } = require('inslash');
const User = require('./models/User');
const sendEmail = require('./utils/email');
// Request password reset
app.post('/forgot-password', async (req, res) => {
const { email } = req.body;
// Find user
const user = await User.findOne({ email });
if (!user) {
// Don't reveal if email exists
return res.json({ message: 'If email exists, reset link sent' });
}
// Generate reset token
const resetToken = crypto.randomBytes(32).toString('hex');
const resetTokenHash = crypto.createHash('sha256').update(resetToken).digest('hex');
user.resetPasswordToken = resetTokenHash;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
await user.save();
// Send email
const resetUrl = \`https://yourapp.com/reset-password/\${resetToken}\`;
await sendEmail({
to: user.email,
subject: 'Password Reset Request',
html: \`Click here to reset: \${resetUrl}\`
});
res.json({ message: 'If email exists, reset link sent' });
});
// Reset password with token
app.post('/reset-password/:token', async (req, res) => {
const { password } = req.body;
// Hash the token to compare
const resetTokenHash = crypto.createHash('sha256')
.update(req.params.token)
.digest('hex');
// Find user with valid token
const user = await User.findOne({
resetPasswordToken: resetTokenHash,
resetPasswordExpires: { $gt: Date.now() }
});
if (!user) {
return res.status(400).json({ error: 'Invalid or expired token' });
}
// Hash new password
const hashResult = await hash(password, process.env.HASH_PEPPER, {
algorithm: 'sha512',
iterations: 150000
});
// Update user
user.passport = hashResult.passport;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
await user.save();
res.json({ success: true, message: 'Password reset successful' });
});
Configuration
Recommended security settings:
Production Recommendation: Use SHA-512 with 150,000+ iterations for maximum security.
// Production configuration
const productionConfig = {
algorithm: 'sha512', // Strongest algorithm
iterations: 150000,
saltLength: 16,
hashLength: 64
};
// Use it
const result = await hash(password, process.env.HASH_PEPPER, productionConfig);