Authentication Model
mailiam’s Adaptive Authentication
Section titled “mailiam’s Adaptive Authentication”mailiam uses a sophisticated multi-layer authentication model that provides both maximum security and developer convenience. Unlike traditional APIs that require API keys for everything, mailiam intelligently adapts authentication based on your use case.
Three-Tier Key System
Section titled “Three-Tier Key System”mailiam provides three types of API keys, each designed for specific use cases:
1. Admin Keys (mlm_sk_admin_*)
Section titled “1. Admin Keys (mlm_sk_admin_*)”Full account access - Complete control over your mailiam account.
Use for:
- CLI operations (
mailiam push,mailiam pull) - Domain management
- API key management
- Billing and account settings
- All administrative operations
Security level: 🔴 Critical - Never expose client-side
Example:
mlm_sk_admin_a1b2c3d4e5f6g7h8...Storage:
- Store in
.envfiles (server-side only) - Use in CI/CD pipelines
- Keep in secure vaults (AWS Secrets Manager, etc.)
2. Usage Keys (mlm_sk_usage_*)
Section titled “2. Usage Keys (mlm_sk_usage_*)”Limited operational access - Form submissions and email sending only.
Use for:
- Vercel/Netlify API routes
- Backend services
- Programmatic form submissions
- Email sending operations
Security level: 🟡 Moderate - Safe in server environments, not client-side
Permissions:
forms:send- Submit contact formsemail:send- Send transactional emails- ❌ Cannot manage domains
- ❌ Cannot create/delete API keys
- ❌ Cannot access billing
Example:
mlm_sk_usage_x9y8z7w6v5u4t3s2...Storage:
- Vercel/Netlify environment variables
- Backend
.envfiles - Container secrets
3. Public Tokens (mlm_pk_*)
Section titled “3. Public Tokens (mlm_pk_*)”Domain-specific, safe for client-side - Limited to one domain, read-only operations.
Use for:
- Static websites
- Client-side JavaScript
- Embedded forms
- Public-facing integrations
Security level: 🟢 Safe - Can be exposed in client-side code
Characteristics:
- Domain-scoped - Only works for ONE specific domain
- Limited permissions - Can only submit forms for the scoped domain
- Lower rate limits - 100 requests/hour (vs 1000 for other keys)
- Cannot be used for - Managing settings, accessing other domains, admin operations
Example:
mlm_pk_a7f8b3e1_j4k5l6m7n8o9p0q1... ^^^^^^^^^ Domain hash - identifies the scoped domainUsage:
// Safe to embed in client-side code!fetch('https://api.mailiam.dev/v1/mysite.com/send', { method: 'POST', headers: { 'X-Public-Token': 'mlm_pk_a7f8b3e1_j4k5l6m7n8o9p0q1...' }, body: formData})Authentication Decision Tree
Section titled “Authentication Decision Tree”Choose the right authentication method for your deployment:
┌─ Need to manage domains/settings? ────────► Admin Key (server-side only)│├─ Building a backend API/service? ─────────► Usage Key (server-side)│├─ Static site with simple forms? ──────────► No API key needed!*│ (Origin validation)│└─ Static site needing JS interactions? ────► Public Token (client-side safe) (checking status, analytics, etc.)
* Forms work without API keys when using origin validationSecurity Model by Deployment Type
Section titled “Security Model by Deployment Type”Static Sites (Cloudflare Pages, GitHub Pages)
Section titled “Static Sites (Cloudflare Pages, GitHub Pages)”Option 1: No API Key (Recommended)
Forms work automatically with origin validation:
<!-- No API key needed! --><form action="https://api.mailiam.dev/v1/mysite.com/send" method="POST"> <input name="email" type="email" required> <textarea name="message" required></textarea> <button type="submit">Send</button></form>How it’s secure:
- ✅ Domain verification (DNS records)
- ✅ Origin header validation
- ✅ Browser detection (blocks curl, Postman)
- ✅ IP-based rate limiting
- ✅ Spam protection
Option 2: Public Token (For Advanced Features)
Use when you need JavaScript interactions:
// Safe for static sitesconst publicToken = 'mlm_pk_a7f8b3e1_j4k5l6m7n8o9p0q1...';
// Submit formawait fetch('https://api.mailiam.dev/v1/mysite.com/send', { headers: { 'X-Public-Token': publicToken }, method: 'POST', body: formData});
// Check submission status (future feature)await fetch('https://api.mailiam.dev/v1/mysite.com/status/sub_123', { headers: { 'X-Public-Token': publicToken }});SSR Sites (Vercel, Netlify Functions)
Section titled “SSR Sites (Vercel, Netlify Functions)”Use Usage Keys in API Routes
Hide the API key server-side:
// pages/api/contact.js (Next.js example)export default async function handler(req, res) { const response = await fetch( 'https://api.mailiam.dev/v1/mysite.com/send', { method: 'POST', headers: { 'X-Api-Key': process.env.MAILIAM_USAGE_KEY // Server-side only }, body: JSON.stringify(req.body) } );
res.json(await response.json());}Benefits:
- ✅ API key never exposed to client
- ✅ Add custom validation
- ✅ Transform data before sending
- ✅ Implement your own rate limiting
Backend Services (Node.js, Python, etc.)
Section titled “Backend Services (Node.js, Python, etc.)”Use Admin or Usage Keys
Depending on what operations you need:
// Full control with Admin Keyconst adminKey = process.env.MAILIAM_ADMIN_KEY;
// Create domains, manage settings, etc.await fetch('https://api.mailiam.dev/domains', { headers: { 'Authorization': `Bearer ${adminKey}` }});// Just send emails with Usage Keyconst usageKey = process.env.MAILIAM_USAGE_KEY;
await fetch('https://api.mailiam.dev/v1/mysite.com/send', { headers: { 'X-Api-Key': usageKey }, method: 'POST', body: formData});Creating API Keys
Section titled “Creating API Keys”Via CLI (Recommended)
Section titled “Via CLI (Recommended)”# Create admin key (default)mailiam auth create-key --name "Production Admin"
# Create usage key for API routesmailiam auth create-key \ --name "Vercel API Route" \ --type usage
# Create public token for a domainmailiam auth create-key \ --name "Public Token for mysite.com" \ --type public \ --domain mysite.comVia API
Section titled “Via API”curl -X POST https://api.mailiam.dev/api-keys \ -H "Authorization: Bearer $MAILIAM_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Public Token for mysite.com", "keyType": "public", "domainScope": "mysite.com" }'Response
Section titled “Response”{ "success": true, "apiKey": { "keyId": "key_abc123", "name": "Public Token for mysite.com", "keyType": "public", "domainScope": "mysite.com", "key": "mlm_pk_a7f8b3e1_j4k5l6m7n8o9p0q1...", "rateLimit": 100 }, "message": "Public key created successfully. Save the key securely - it will not be shown again.", "securityNote": "This public key is safe for client-side use but is scoped to the specified domain only."}Security Best Practices
Section titled “Security Best Practices”1. Choose the Right Key Type
Section titled “1. Choose the Right Key Type”| Scenario | Key Type | Reasoning |
|---|---|---|
| CLI operations | Admin | Need full account access |
| Vercel API route | Usage | Only need to send emails |
| Static website form | None or Public | Origin validation sufficient |
| JavaScript interactions | Public | Safe for client-side |
2. Never Expose Admin Keys
Section titled “2. Never Expose Admin Keys”// ❌ NEVER DO THISconst adminKey = 'mlm_sk_admin_...';fetch('https://api.mailiam.dev/domains', { headers: { 'Authorization': `Bearer ${adminKey}` }});// ✅ DO THIS INSTEAD// Use a public token or no key at all for static sites3. Rotate Keys Regularly
Section titled “3. Rotate Keys Regularly”# Create new keymailiam auth create-key --name "Production v2" --type usage
# Test new keyexport MAILIAM_API_KEY="new_key"mailiam test config
# Update environment variables
# Revoke old keymailiam auth revoke-key key_old1234. Use Environment Variables
Section titled “4. Use Environment Variables”# .env.local (never commit!)MAILIAM_ADMIN_KEY=mlm_sk_admin_...MAILIAM_USAGE_KEY=mlm_sk_usage_...
# .env.production (Vercel/Netlify)MAILIAM_API_KEY=mlm_sk_usage_...5. Monitor API Key Usage
Section titled “5. Monitor API Key Usage”# View usage by keymailiam analytics api-usage --key key_abc123
# Check for suspicious activitymailiam auth list-keys --show-last-usedMigration from Single Key System
Section titled “Migration from Single Key System”If you’re upgrading from an older mailiam version with a single key type:
Your existing keys still work!
Section titled “Your existing keys still work!”All legacy keys (mlm_...) are treated as admin keys for backward compatibility.
Recommended upgrade path:
Section titled “Recommended upgrade path:”-
Create new key types
Terminal window # For Vercel/Netlifymailiam auth create-key --type usage --name "API Routes"# For static sitesmailiam auth create-key --type public --domain mysite.com -
Update your applications
- Update environment variables
- Test thoroughly
- Deploy changes
-
Revoke old keys (optional)
Terminal window mailiam auth revoke-key key_old123
Comparison with Other Services
Section titled “Comparison with Other Services”| Service | Client-Side Keys | Domain Scoping | Origin Validation |
|---|---|---|---|
| mailiam | ✅ Public Tokens | ✅ Per-domain | ✅ Built-in |
| Resend | ❌ No | ❌ Account-wide | ❌ Manual |
| SendGrid | ❌ No | ❌ Account-wide | ❌ Manual |
| EmailJS | ✅ Public Keys | ❌ Account-wide | ❌ Manual |
Technical Details
Section titled “Technical Details”Key Format Specification
Section titled “Key Format Specification”Admin Keys: mlm_sk_admin_{64_hex_chars}Usage Keys: mlm_sk_usage_{64_hex_chars}Public Keys: mlm_pk_{8_hex_domain_hash}_{64_hex_chars}Rate Limits by Key Type
Section titled “Rate Limits by Key Type”| Key Type | Default Rate Limit | Can Be Customized |
|---|---|---|
| Admin | 1000/hour | ✅ Yes |
| Usage | 1000/hour | ✅ Yes |
| Public | 100/hour | ⚠️ Limited |
Storage & Hashing
Section titled “Storage & Hashing”- Keys are hashed using SHA-256 before storage
- Only the hash is stored in the database
- Original key is shown only once at creation
- Cannot retrieve original key after creation
Need Help?
Section titled “Need Help?”Common Questions
Section titled “Common Questions”Q: Can I use a public token for multiple domains? A: No, public tokens are scoped to a single domain for security.
Q: What happens if I expose an admin key accidentally?
A: Immediately revoke it using mailiam auth revoke-key and create a new one.
Q: Do I need API keys for simple contact forms? A: No! Forms work without API keys using origin validation.
Q: Can I increase the rate limit for public tokens? A: Public tokens have lower limits by design. Use a usage key in an API route for higher limits.
Resources
Section titled “Resources”The key to security is using the right key for the right job. Choose wisely! 🔐