🔌 Dymo API in Better-Auth
Take Better-Auth security to the next level with built-in resilience system.
Overview
In order to facilitate the use of Dymo API in applications that integrate Better-Auth, we have launched a new library specialized in projects that use Better-Auth as an authentication system. This integration includes the complete resilience system for reliable API operations during authentication flows.
Installation
npm install @dymo-api/better-auth
#or
pnpm install @dymo-api/better-auth
#or
yarn add @dymo-api/better-auth
Plugin Features
Sign Up General Protection (Coming Soon)
User-Agent Validation (Coming Soon)
Resilience System
All Better-Auth plugins come with the built-in resilience system that provides:
- 🔄 Automatic Retries: Configurable retry attempts with exponential backoff
- 🚦 Rate Limiting: Intelligent tracking and management of API rate limits
- 🛡️ Fallback Data: Automatic generation of safe fallback responses when API is unavailable
- ⚡ Smart Error Handling: Differentiates between retry-worthy and non-retry-worthy errors
- 🔐 Seamless Integration: Works automatically during authentication flows
Basic Configuration
import { betterAuth } from "better-auth";
import { dymoEmailPlugin } from "@dymo-api/better-auth";
const auth = betterAuth({
// Your Better-Auth configuration
emailAndPassword: { ... },
socialProviders: { ... },
// Dymo plugins with resilience
plugins: [
dymoEmailPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
emailRules: {
deny: ["FRAUD", "INVALID", "DISPOSABLE"]
},
resilience: {
fallbackEnabled: true, // Enable fallback data generation
retryAttempts: 2, // Number of additional retry attempts
retryDelay: 500 // Base delay in milliseconds
}
}),
dymoIPPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
ipRules: {
deny: ["FRAUD", "TOR_NETWORK"]
},
resilience: {
fallbackEnabled: true,
retryAttempts: 1,
retryDelay: 200
}
})
]
});
Production vs Development
const productionAuth = betterAuth({
plugins: [
dymoEmailPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
emailRules: { deny: ["FRAUD", "INVALID", "DISPOSABLE"] },
resilience: {
fallbackEnabled: true, // Keep authentication working during outages
retryAttempts: 2, // 1 normal + 2 retries = 3 total attempts
retryDelay: 500 // Faster retries for better UX
}
}),
dymoIPPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
ipRules: { deny: ["FRAUD", "TOR_NETWORK"] },
resilience: {
fallbackEnabled: true,
retryAttempts: 1,
retryDelay: 200
}
})
]
});
// Benefits:
// ✅ Users can authenticate even during API issues
// ✅ Balanced security and user experience
// ✅ Automatic fallback to safe responses
Benefits:
- ✅ User authentication maintained during API issues
- ✅ Balanced retry speed and reliability
- ✅ Automatic fallback to safe responses
- ✅ Better user experience during temporary issues
Usage Examples
Email Validation with Resilience
import { betterAuth } from "better-auth";
import { dymoEmailPlugin } from "@dymo-api/better-auth";
const auth = betterAuth({
emailAndPassword: {
enabled: true,
requireEmailVerification: true
},
plugins: [
dymoEmailPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
emailRules: { deny: ["FRAUD", "INVALID"] },
resilience: {
fallbackEnabled: true,
retryAttempts: 2,
retryDelay: 500
}
})
]
});
// The plugin will automatically:
// 1. Validate email on sign-up, sign-in, password reset
// 2. Retry on network failures with exponential backoff
// 3. Use fallback data if API is completely unavailable
// 4. Block fraudulent emails during authentication flows
IP Validation with Resilience
import { betterAuth } from "better-auth";
import { dymoIPPlugin } from "@dymo-api/better-auth";
const auth = betterAuth({
plugins: [
dymoIPPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
// Strict IP validation rules
ipRules: {
deny: [
"FRAUD", // Block fraudulent IP addresses
"TOR_NETWORK", // Block Tor exit nodes
"HIGH_RISK_SCORE", // Block high-risk IP ranges
"PROXY", // Block known proxy servers
"COUNTRY:RU", // Block specific countries if needed
"COUNTRY:CN" // Block specific countries if needed
]
},
resilience: {
fallbackEnabled: true,
retryAttempts: 1,
retryDelay: 200
}
})
]
});
// The plugin automatically:
// 1. Extracts IP from common headers: x-forwarded-for, cf-connecting-ip, etc.
// 2. Validates IP on authentication attempts
// 3. Retries on network failures
// 4. Blocks requests from problematic IPs
// 5. Normalizes IP in request context if successful
Phone Validation with Resilience
import { betterAuth } from "better-auth";
import { dymoPhonePlugin } from "@dymo-api/better-auth";
const auth = betterAuth({
phoneNumber: { enabled: true },
plugins: [
dymoPhonePlugin({
apiKey: "PRIVATE_TOKEN_HERE",
// Phone validation rules
phoneRules: {
deny: [
"FRAUD", // Block fraudulent phone numbers
"INVALID", // Block invalid format numbers
"VOIP", // Optionally block VOIP numbers
"PREMIUM_RATE" // Optionally block premium rate numbers
]
},
resilience: {
fallbackEnabled: true,
retryAttempts: 1,
retryDelay: 300
}
})
]
});
// Validates phone numbers on:
// - /sign-in/phone-number
// - /phone-number/forget-password
// - /phone-number/send-otp
// - /phone-number/verify
Error Handling & Monitoring
Monitoring Resilience
Monitor console for resilience warnings during authentication flows to understand API behavior and user experience impact.
Common log messages during authentication:
[WARN] [Dymo API] Client xxx is rate limited. Waiting 60 seconds...
# User authentication temporarily delayed
[WARN] [Dymo API] Attempt 1 failed. Retrying in 500ms...
# Authentication temporarily paused, but will retry
[WARN] [Dymo API] Request failed after 3 attempts. Using fallback data.
# Authentication continues with safe fallback response
Fallback Behavior in Authentication
When fallbackEnabled: true and all retries fail during authentication:
// Example: Email validation fallback during user registration
const auth = betterAuth({
plugins: [
dymoEmailPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
resilience: { fallbackEnabled: true }
})
]
});
// If API fails completely during sign-up:
// - User will be blocked (safe fallback = allow: false)
// - Registration will fail gracefully
// - No user data leaked due to fallback
// - Authentication system remains functional
// Fallback email response:
// {
// email: "[email protected]",
// allow: false,
// reasons: ["INVALID"]
// }
Rate Limiting in Authentication
The Better-Auth SDK automatically handles rate limiting during authentication flows:
// Multiple concurrent authentication attempts
const handleBurst = async (authRequests: Request[]) => {
// The SDK will automatically:
// 1. Track rate limits per client (API key)
// 2. Respect retry-after headers on 429 responses
// 3. Queue requests during rate limit periods
// 4. Not retry rate-limited requests (wait instead)
// Results in graceful degradation rather than complete failures
const results = await Promise.allSettled(authRequests);
return results;
};
Best Practices
Security Configuration
const strictAuth = betterAuth({
plugins: [
dymoEmailPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
emailRules: {
deny: [
"FRAUD", "INVALID", "DISPOSABLE",
"NO_MX_RECORDS", "HIGH_RISK_SCORE",
"NO_REPLY_EMAIL", "FREE_EMAIL"
]
},
resilience: {
fallbackEnabled: false, // No fallbacks for high security
retryAttempts: 1, // Minimal retries
retryDelay: 1500 // Cautious retry timing
}
}),
dymoIPPlugin({
apiKey: "PRIVATE_TOKEN_HERE",
ipRules: {
deny: [
"FRAUD", "TOR_NETWORK", "HIGH_RISK_SCORE",
"PROXY", "VPN", "COUNTRY:RU", "COUNTRY:CN"
]
},
resilience: {
fallbackEnabled: false,
retryAttempts: 1,
retryDelay: 2000
}
})
]
});
// Benefits:
// ✅ Maximum security validation
// ✅ No acceptance of potentially invalid data
// ✅ Fail-safe approach for sensitive operations
// ✅ Protection against edge cases and bypasses
Use Cases:
- Financial applications
- High-security authentication
- Compliance-required systems
- Sensitive data protection
Performance Optimization
// Cache validation results to reduce API calls during authentication
const validationCache = new Map<string, { result: boolean, timestamp: number }>();
const cachedValidationPlugin = (options: any) => {
const plugin = dymoEmailPlugin({
...options,
resilience: { fallbackEnabled: true, retryAttempts: 2, retryDelay: 500 }
});
// Add caching middleware around the plugin
const originalMatcher = plugin.hooks?.before?.[0]?.matcher;
if (originalMatcher) {
plugin.hooks!.before![0].matcher = (context: any) => {
const email = context.body?.email;
// Check cache first
if (email && validationCache.has(email)) {
const cached = validationCache.get(email)!;
if (Date.now() - cached.timestamp < 300000) { // 5 minutes
if (!cached.result) {
throw new Error("Cached: Email is invalid or blocked");
}
return originalMatcher(context);
}
}
return originalMatcher(context);
};
}
return plugin;
};
// Clear cache periodically
setInterval(() => {
const now = Date.now();
for (const [key, value] of validationCache.entries()) {
if (now - value.timestamp > 300000) { // 5 minutes
validationCache.delete(key);
}
}
}, 60000); // Check every minute
Benefits:
- ✅ Reduced API calls and costs
- ✅ Faster authentication for repeat users
- ✅ Automatic cache management
- ✅ Still maintains resilience for cache misses
Migration from Previous Version
Updating from Manual Validation
// ❌ Manual validation without resilience
import { betterAuth } from "better-auth";
const oldAuth = betterAuth({
emailAndPassword: { enabled: true },
// ❌ Manual middleware with no resilience
middleware: {
before: [
{
matcher: (context) => context.path === "/sign-up",
handler: async (ctx) => {
// ❌ Single API call with no retry logic
const response = await fetch('/api/validate-email', {
method: 'POST',
body: JSON.stringify({ email: ctx.body.email })
});
if (!response.ok) {
// ❌ Immediate failure on network issues
throw new Error("Invalid email");
}
// ❌ No fallback handling
// ❌ No rate limit management
// ❌ Poor user experience during API issues
}
}
]
}
});
Problems:
- ❌ Manual error handling required
- ❌ No automatic recovery from failures
- ❌ Poor user experience during API issues
- ❌ No rate limit management
- ❌ Maintenance burden on development team
Updating Configuration
If you were using previous resilience configuration:
// Previous behavior (3 total attempts max)
emailPlugin: {
resilience: { retryAttempts: 2 } // Was: 1 normal + 2 retries = 3 total
}
// Same behavior now
emailPlugin: {
resilience: { retryAttempts: 2 } // Still: 1 normal + 2 retries = 3 total
}
The resilience behavior remains the same - only the parameter documentation has been clarified. Your existing code will continue to work without changes.
Support
Common Issues
Getting Help
If you encounter issues with the Better-Auth SDK resilience system:
- Check Console: Look for resilience warning messages during authentication
- Verify Configuration: Ensure resilience options are properly set in plugins
- Test Network: Check internet connectivity and API access
- Monitor Status: Check API Status Page
- Review Rules: Validate your email/IP/phone rules configuration
- Contact Support: Include logs, configuration, and authentication flow details
When reporting issues, please include:
- Your plugin configuration (with resilience settings)
- Relevant console logs from authentication attempts
- Validation rules being applied
- Authentication flows where issues occur
- Your API key (last 4 characters only)