Push Authentication Guide
Implement secure, frictionless authentication with push notifications.
How It Works
User initiates login
User enters username on your login page
Your server calls AffirmID
Create an auth request via our API
Push sent to user
User receives notification on their registered device
User approves/denies
User taps Approve or Deny in the app
Result returned
Your server receives the decision via webhook or polling
Key Features
One-Tap Approval
Users approve or deny requests with a single tap on their mobile device.
Rich Context
Show location, device, app name, and custom messages in the push notification.
Configurable Timeout
Set custom expiration times from 30 seconds to 10 minutes.
Biometric Confirmation
Optionally require Face ID or fingerprint before approval.
Implementation
1. Create an Authentication Request
const request = await affirmid.auth.create({
// Required
userId: 'user_123', // Your internal user ID
// Recommended
application: 'Acme Dashboard', // Shown in the push notification
ipAddress: req.ip, // For location context
userAgent: req.headers['user-agent'],
// Optional
message: 'Login from Chrome on Windows', // Custom message
timeout: 120, // Seconds until expiration (default: 60)
requireBiometric: true, // Require Face ID/fingerprint
// Custom data (returned in webhooks)
metadata: {
sessionId: 'sess_abc123',
loginAttemptId: 'attempt_xyz'
}
});
console.log(request);
// {
// id: 'auth_xxxxxxxxxxxx',
// status: 'pending',
// expiresAt: '2024-01-15T12:00:00Z',
// userId: 'user_123'
// }2. Wait for the Result
You can either poll for the result or use webhooks:
Option A: Polling
// Simple polling
const result = await affirmid.auth
.waitForResult(request.id, {
timeout: 60000, // 60 seconds
interval: 1000 // Check every second
});
if (result.decision === 'approved') {
// Grant access
}Option B: Webhooks
// Express webhook handler
app.post('/webhooks/affirmid',
affirmid.webhooks.verify(),
(req, res) => {
const { authRequestId,
decision } = req.body;
// Update your session
res.sendStatus(200);
}
);3. Handle the Decision
switch (result.decision) {
case 'approved':
// User approved - grant access
await createSession(result.userId);
res.redirect('/dashboard');
break;
case 'denied':
// User explicitly denied
res.status(401).json({ error: 'Authentication denied by user' });
break;
case 'expired':
// Request timed out
res.status(401).json({ error: 'Authentication request expired' });
break;
}
// Full result object:
// {
// id: 'auth_xxxxxxxxxxxx',
// decision: 'approved',
// decidedAt: '2024-01-15T12:00:30Z',
// deviceId: 'device_yyyyyyy',
// location: { city: 'San Francisco', country: 'US' },
// biometricUsed: true,
// metadata: { sessionId: 'sess_abc123' }
// }Best Practices
Always include context
Provide IP address, user agent, and location so users can make informed decisions about approval.
Set appropriate timeouts
60 seconds works well for most cases. Increase for mobile-first workflows where users might need more time.
Use webhooks in production
Webhooks are more efficient than polling and provide real-time results without keeping connections open.
Provide fallback options
Allow users to authenticate via TOTP if push notifications fail or their device is unavailable.
Error Handling
| Error Code | Description | Resolution |
|---|---|---|
user_not_found | No user with this ID exists | Verify the userId matches your system |
no_devices | User has no registered devices | Prompt user to set up the mobile app |
push_failed | Failed to deliver push notification | Fall back to TOTP authentication |
rate_limited | Too many requests for this user | Wait before retrying |
Next Steps
Explore other authentication methods and advanced features.