Security Best Practices

Security is a top priority at Notifs. This guide covers best practices for keeping your integration secure.

API Key Management

Store Keys Securely

Never commit API keys to version control. Always use environment variables:

# .env
NOTIFS_API_KEY=notifs_sk_...
// ✅ Good
const notifs = new Notifs({
  apiKey: process.env.NOTIFS_API_KEY
})

// ❌ Bad
const notifs = new Notifs({
  apiKey: 'notifs_sk_abc123...' // Never hardcode!
})

Rotate Keys Regularly

Rotate your API keys periodically, especially if:

  • A team member with access leaves
  • You suspect a key has been compromised
  • As part of regular security hygiene (every 90 days)

Use Restricted Keys

Create separate API keys for different environments and services:

# Development
NOTIFS_API_KEY=notifs_sk_dev_...

# Production
NOTIFS_API_KEY=notifs_sk_prod_...

Webhook Signature Verification

All webhooks sent from Notifs include HMAC-SHA256 signatures. Always verify these signatures to ensure webhooks are genuine.

How It Works

  1. Notifs signs each webhook request with your webhook secret
  2. The signature is sent in the X-Notifs-Signature header
  3. You verify the signature using the same secret

Implementation

import crypto from 'crypto'

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const hmac = crypto.createHmac('sha256', secret)
  hmac.update(payload)
  const expectedSignature = hmac.digest('hex')

  // Use timing-safe comparison to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  )
}

// In your webhook handler
app.post('/webhooks/notifs', (req, res) => {
  const signature = req.headers['x-notifs-signature']
  const payload = JSON.stringify(req.body)

  if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' })
  }

  // Process webhook...
  res.json({ success: true })
})

Next.js App Router Example

// app/api/webhooks/route.ts
import { NextRequest, NextResponse } from 'next/server'
import crypto from 'crypto'

function verifySignature(payload: string, signature: string): boolean {
  const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET!)
  hmac.update(payload)
  const expectedSignature = hmac.digest('hex')

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  )
}

export async function POST(request: NextRequest) {
  const signature = request.headers.get('x-notifs-signature')
  if (!signature) {
    return NextResponse.json({ error: 'Missing signature' }, { status: 401 })
  }

  const payload = await request.text()

  if (!verifySignature(payload, signature)) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })
  }

  const data = JSON.parse(payload)

  // Process webhook securely...
  return NextResponse.json({ success: true })
}

Rate Limiting

Notifs implements rate limiting to prevent abuse:

Default Limits

  • Free Tier: 10 requests/second, 1,000 requests/month
  • Pro Tier: 100 requests/second, 100,000 requests/month
  • Enterprise: Custom limits

Handle Rate Limits

Implement exponential backoff when you hit rate limits:

async function sendWithRetry(
  webhookId: string,
  data: any,
  maxRetries = 3
): Promise<WebhookResponse> {
  let retries = 0

  while (retries < maxRetries) {
    try {
      return await notifs.webhooks.send(webhookId, data)
    } catch (error) {
      if (error instanceof RateLimitError) {
        const delay = Math.pow(2, retries) * 1000 // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay))
        retries++
      } else {
        throw error
      }
    }
  }

  throw new Error('Max retries exceeded')
}

Idempotency

Use idempotency keys to prevent duplicate webhook sends:

await notifs.webhooks.send('webhook_id', data, {
  idempotencyKey: `payment_${paymentId}` // Unique key per operation
})

If the same idempotency key is used within 24 hours, Notifs will return the cached response instead of sending a duplicate webhook.

Input Validation

Always validate and sanitize data before sending:

import { z } from 'zod'

const PaymentSchema = z.object({
  userId: z.string(),
  amount: z.number().positive(),
  currency: z.enum(['USD', 'EUR', 'GBP']),
  email: z.string().email()
})

async function sendPaymentNotification(data: unknown) {
  // Validate input
  const validated = PaymentSchema.parse(data)

  // Send notification with validated data
  await notifs.webhooks.send('webhook_id', validated)
}

HTTPS Only

Notifs only accepts requests over HTTPS. Make sure your webhook endpoints also use HTTPS in production.

// ✅ Good
const webhookUrl = 'https://yourapp.com/webhooks/notifs'

// ❌ Bad (will fail in production)
const webhookUrl = 'http://yourapp.com/webhooks/notifs'

Content Security Policy

Add appropriate CSP headers to your API routes:

export async function POST(request: NextRequest) {
  const response = NextResponse.json({ success: true })

  response.headers.set(
    'Content-Security-Policy',
    "default-src 'none'; frame-ancestors 'none'"
  )

  return response
}

Monitoring and Alerts

Set up monitoring for suspicious activity:

  • Failed authentication attempts
  • Unusual request patterns
  • High error rates
  • Rate limit hits

Use Notifs request logs to track and investigate issues:

const logs = await notifs.logs.list({
  status: 'failed',
  startDate: new Date(Date.now() - 24 * 60 * 60 * 1000) // Last 24h
})

if (logs.data.length > 10) {
  console.warn('High number of failed requests detected!')
}

Data Privacy

PII Handling

Be mindful of personally identifiable information (PII):

  • Don't include sensitive data in webhook payloads unless necessary
  • Use references/IDs instead of full user data when possible
  • Comply with GDPR, CCPA, and other privacy regulations
// ✅ Good
await notifs.webhooks.send('webhook_id', {
  userId: 'user_123',
  event: 'password_reset_requested'
})

// ❌ Avoid when possible
await notifs.webhooks.send('webhook_id', {
  email: 'user@example.com',
  socialSecurityNumber: '123-45-6789', // Never!
  creditCard: '4111111111111111' // Never!
})

Compliance

Notifs is compliant with:

  • SOC 2 Type II
  • GDPR
  • CCPA
  • HIPAA (Enterprise plan)

For enterprise compliance requirements, contact enterprise@notifs.dev.

Security Incident Response

If you suspect a security incident:

  1. Rotate your API keys immediately
  2. Review recent logs for suspicious activity
  3. Contact our security team: security@notifs.dev
  4. Document the incident and affected resources

Bug Bounty Program

We run a bug bounty program. If you discover a security vulnerability, please report it responsibly to security@notifs.dev.

Do not:

  • Test against production without permission
  • Access or modify data that doesn't belong to you
  • Perform DoS attacks
  • Publicly disclose vulnerabilities before we've had time to patch

Next Steps