📋 Implementation Code
Here's the code you would use in your SaaS:
// Your SaaS backend code
const response = await fetch('/pow/simple-verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
challengeId: 'challenge-id',
nonce: 'solution-nonce',
userAgent: navigator.userAgent,
ipAddress: '192.168.1.1',
siteKey: 'your-site-key'
})
});
const result = await response.json();
if (result.valid) {
console.log('User verified!');
// Allow access to your SaaS
} else {
console.log('Verification failed:', result.message);
}
🌐 API Endpoints Reference
Complete API documentation for integration:
📤 POST /pow/simple-verify
Purpose: Verify a POW solution (the main endpoint your SaaS uses)
Required: challengeId, nonce
Optional: userAgent, ipAddress, siteKey
Returns: valid (boolean), verificationToken (string), message (string)
// Request
{
"challengeId": "uuid",
"nonce": "solution-number",
"userAgent": "browser-info",
"ipAddress": "user-ip",
"siteKey": "your-identifier"
}
// Response (Success)
{
"valid": true,
"verificationToken": "base64-token",
"message": "Verified successfully",
"expiresIn": "1 hour"
}
// Response (Failure)
{
"valid": false,
"message": "Invalid proof of work"
}
🔍 POST /pow/verify-token
Purpose: Check if a verification token is still valid
Required: token
Returns: valid (boolean), payload (object)
// Request
{
"token": "base64-verification-token"
}
// Response
{
"valid": true,
"payload": {
"challengeId": "uuid",
"siteKey": "your-identifier",
"expiresAt": "2024-01-01T12:00:00Z"
}
}
📥 GET /pow/challenge
Purpose: Generate a new challenge for users to solve
Optional: difficulty (default: 16)
Returns: challengeId, challenge, difficulty, expiresAt
// Request
GET /pow/challenge?difficulty=8
// Response
{
"challengeId": "uuid",
"challenge": "random-hex-string",
"difficulty": 8,
"expiresAt": "2024-01-01T12:10:00Z"
}
🔧 Common Integration Patterns
Real-world implementation examples:
🛡️ Middleware Pattern (Recommended)
// Express.js middleware
function requirePowVerification(req, res, next) {
const token = req.session.powToken;
if (!token) {
// Redirect to POW challenge
const callback = `${req.protocol}://${req.get('host')}/pow-callback`;
const challengeUrl = `${POW_SERVICE}/pow-challenge?callback=${encodeURIComponent(callback)}`;
return res.redirect(challengeUrl);
}
next();
}
// Use on protected routes
app.get('/dashboard', requirePowVerification, (req, res) => {
res.render('dashboard');
});
📞 Callback Handler Pattern
// Handle POW solutions from challenge page
app.post('/pow-callback', async (req, res) => {
const { challengeId, nonce, userAgent, ipAddress } = req.body;
// Verify with ONE POST request
const response = await fetch(`${POW_SERVICE}/pow/simple-verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
challengeId,
nonce,
userAgent,
ipAddress,
siteKey: 'my-saas-app'
})
});
const result = await response.json();
if (result.valid) {
// Store verification
req.session.powVerified = true;
req.session.powToken = result.verificationToken;
res.json({ success: true, redirectUrl: '/dashboard' });
} else {
res.json({ success: false, message: result.message });
}
});
🔄 Session Management Pattern
// Check verification status
function isPowVerified(req) {
return req.session.powVerified === true;
}
// Optional: Verify token is still valid
async function verifyStoredToken(token) {
const response = await fetch(`${POW_SERVICE}/pow/verify-token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token })
});
const result = await response.json();
return result.valid;
}