Security Best Practices

Overview

This guide covers security best practices for using the Form Platform securely.

For Users

API Key Management

Key Security:

  • ✅ Rotate API keys regularly (every 90 days)

  • ✅ Use environment-specific keys

  • ✅ Never commit keys to version control

  • ✅ Store keys in environment variables

  • ✅ Delete unused keys immediately

  • ✅ Monitor key usage regularly

Key Rotation:

# 1. Create new key
curl -X POST /keys/secrets?environment=production

# 2. Update integrations with new key
# Update your code/config

# 3. Delete old key
curl -X DELETE /keys/secrets/{oldKeyId}

Environment Management

Best Practices:

  • ✅ Use separate environments for dev/staging/production

  • ✅ Never share API keys between environments

  • ✅ Test changes in development first

  • ✅ Use environment-specific publishable keys

Spam Protection

Enable Protection:

  • ✅ Enable honeypot fields

  • ✅ Configure reCAPTCHA for public forms

  • ✅ Set up custom spam rules

  • ✅ Monitor spam detection rates

Configuration:

{
  "spamProtection": {
    "honeypot": true,
    "recaptcha": {
      "enabled": true,
      "threshold": 0.5
    }
  }
}

PII Handling

Configure Policies:

  • ✅ Mark sensitive fields with pii: true

  • ✅ Use appropriate PII policies

  • ✅ Review PII handling regularly

  • ✅ Use encrypted or dropped for highly sensitive data

Example:

{
  "fields": [
    {
      "id": "email",
      "type": "email",
      "pii": true,
      "piiPolicy": "masked"  // or "encrypted" for higher security
    }
  ]
}

Rate Limiting

Monitor Usage:

  • ✅ Check quota regularly

  • ✅ Upgrade plan before hitting limits

  • ✅ Implement retry logic for 429 errors

  • ✅ Distribute load over time

For Developers

Code Security

Never Commit Secrets:

# ❌ Bad
const apiKey = "sk_live_abc123...";

# ✅ Good
const apiKey = process.env.FORMR_KEY;

Environment Variables:

# .env file (gitignored)
FORMR_KEY=sk_live_...
FORMR_API_URL=https://api.formr.dev

Input Validation

Always Validate:

  • ✅ Validate all user inputs

  • ✅ Use form schema validation

  • ✅ Sanitize user-provided data

  • ✅ Check field types and formats

Example:

// Validate before submission
const form = await formr.forms.get('contact-form');
const validation = validateAnswers(answers, form.fields);
if (!validation.valid) {
  throw new Error('Validation failed');
}

Error Handling

Secure Error Messages:

  • ✅ Don't expose sensitive data in errors

  • ✅ Log errors securely

  • ✅ Handle errors gracefully

  • ✅ Don't leak internal details

Example:

try {
  await formr.forms.submit(formId, answers);
} catch (error) {
  // Log securely (no sensitive data)
  logger.error('Submission failed', { formId, error: error.message });
  
  // Return generic error to user
  return { error: 'Submission failed. Please try again.' };
}

Webhook Security

Verify Signatures:

  • ✅ Always verify webhook signatures

  • ✅ Use webhook secrets

  • ✅ Validate payload structure

  • ✅ Handle errors securely

Example:

import { Formr } from 'formr';

const isValid = await Formr.webhooks.verify(
  signature,
  rawBody,
  process.env.FORMR_WHSEC
);

if (!isValid) {
  return res.status(401).json({ error: 'Invalid signature' });
}

CORS Configuration

Configure Allowed Origins:

  • ✅ Set specific allowed origins (not * for authenticated endpoints)

  • ✅ Use environment-specific origins

  • ✅ Review CORS settings regularly

Security Checklist

Setup

Configuration

Development

Monitoring

Common Mistakes

❌ Don't Do This

// ❌ Committing API keys
const apiKey = "sk_live_abc123...";

// ❌ Using same key for all environments
const apiKey = process.env.FORMR_KEY; // Used in dev and prod

// ❌ Not validating inputs
await formr.forms.submit(formId, userInput); // No validation

// ❌ Exposing errors
catch (error) {
  return { error: error.stack }; // Exposes internal details
}

✅ Do This Instead

// ✅ Environment variables
const apiKey = process.env.FORMR_KEY;

// ✅ Environment-specific keys
const apiKey = process.env[`FORMR_KEY_${environment.toUpperCase()}`];

// ✅ Validate inputs
const validation = validateAnswers(answers, form.fields);
if (!validation.valid) throw new Error('Invalid input');

// ✅ Generic error messages
catch (error) {
  logger.error('Submission failed', error);
  return { error: 'Submission failed. Please try again.' };
}

Next Steps

  • Security - Security overview

  • Data Protection - Encryption and PII

  • Rate Limiting - Rate limits and quotas

  • Compliance - Compliance and audit logging

Last updated